Skip to content

SHA256

Canonical source: protos/lib/crypto/SHA256.protos at locked revision e99b712ecf658a527b1fe82c8beba2c1286d8dc9.

// THE LICENSED WORK IS PROVIDED UNDER THE TERMS OF THE ADAPTIVE PUBLIC LICENSE
// ("LICENSE") AS FIRST COMPLETED BY: Guillermo Adrián Molina. ANY USE, PUBLIC
// DISPLAY, PUBLIC PERFORMANCE, REPRODUCTION OR DISTRIBUTION OF, OR PREPARATION OF
// DERIVATIVE WORKS BASED ON, THE LICENSED WORK CONSTITUTES RECIPIENT'S ACCEPTANCE
// OF THIS LICENSE AND ITS TERMS, WHETHER OR NOT SUCH RECIPIENT READS THE TERMS OF
// THE LICENSE. "LICENSED WORK" AND "RECIPIENT" ARE DEFINED IN THE LICENSE. A COPY
// OF THE LICENSE IS LOCATED IN THE TEXT FILE ENTITLED "LICENSE.TXT" ACCOMPANYING
// THE CONTENTS OF THIS FILE. IF A COPY OF THE LICENSE DOES NOT ACCOMPANY THIS
// FILE, A COPY OF THE LICENSE MAY ALSO BE OBTAINED AT THE FOLLOWING WEB SITE:
// https://github.com/guillermomolina/protos
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
// the specific language governing rights and limitations under the License.
//! The SHA-256 message digest over standard Bytes values.
/// Answers a fresh 32-octet Bytes value holding the SHA-256 digest of `bytes`.
digest: (bytes) => {
mod32: 4294967296
maxBytes: 2305843009213693951
originalSize: bytes.size()
(originalSize > maxBytes).ifTrue(() => {
Error().signal()
})
// Bytes is deliberately not a required public Prelude binding. Latin1
// accepts every octet sequence, so this performs exact standard-Bytes
// argument validation without changing the digest input or result.
ignoredBytesDomainValidation: Encoding.Latin1.decode(bytes)
powers: Array(
1,
2,
4,
8,
16,
32,
64,
128,
256,
512,
1024,
2048,
4096,
8192,
16384,
32768,
65536,
131072,
262144,
524288,
1048576,
2097152,
4194304,
8388608,
16777216,
33554432,
67108864,
134217728,
268435456,
536870912,
1073741824,
2147483648,
4294967296
)
word32: (value) => {
value.mod(mod32)
}
logicalShiftRight: (value, count) => {
word32(value).div(powers[count])
}
rotateRight: (value, count) => {
source: word32(value)
lowPower: powers[count]
wrapPower: powers[32 - count]
word32(
source.div(lowPower) +
source.mod(lowPower) * wrapPower
)
}
xor3Table: Array(0, 1, 2, 3, 1, 0, 3, 2, 2, 3, 0, 1, 3, 2, 1, 0, 1, 0, 3, 2, 0, 1, 2, 3, 3, 2, 1, 0, 2, 3, 0, 1, 2, 3, 0, 1, 3, 2, 1, 0, 0, 1, 2, 3, 1, 0, 3, 2, 3, 2, 1, 0, 2, 3, 0, 1, 1, 0, 3, 2, 0, 1, 2, 3)
chooseTable: Array(0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 0, 2, 2, 1, 1, 3, 3, 0, 0, 2, 2, 1, 1, 3, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3)
majorityTable: Array(0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 2, 0, 1, 2, 3, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 2, 3, 1, 1, 3, 3, 0, 0, 2, 2, 0, 1, 2, 3, 2, 2, 2, 2, 2, 3, 2, 3, 0, 1, 2, 3, 1, 1, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3)
bitwisePair3: (left, middle, right, table) => {
a: word32(left)
b: word32(middle)
c: word32(right)
place: 1
result: 0
remaining: 16
(() => remaining > 0).whileTrue() {
aPair: a.mod(4)
bPair: b.mod(4)
cPair: c.mod(4)
index: aPair * 16 + bPair * 4 + cPair
result = result + table[index] * place
a = a.div(4)
b = b.div(4)
c = c.div(4)
place = place * 4
remaining = remaining - 1
}
result
}
xor3: (left, middle, right) => {
bitwisePair3(left, middle, right, xor3Table)
}
choose: (x, y, z) => {
bitwisePair3(x, y, z, chooseTable)
}
majority: (x, y, z) => {
bitwisePair3(x, y, z, majorityTable)
}
upperSigma0: (value) => {
xor3(
rotateRight(value, 2),
rotateRight(value, 13),
rotateRight(value, 22)
)
}
upperSigma1: (value) => {
xor3(
rotateRight(value, 6),
rotateRight(value, 11),
rotateRight(value, 25)
)
}
lowerSigma0: (value) => {
xor3(
rotateRight(value, 7),
rotateRight(value, 18),
logicalShiftRight(value, 3)
)
}
lowerSigma1: (value) => {
xor3(
rotateRight(value, 17),
rotateRight(value, 19),
logicalShiftRight(value, 10)
)
}
roundConstants: Array(
1116352408,
1899447441,
3049323471,
3921009573,
961987163,
1508970993,
2453635748,
2870763221,
3624381080,
310598401,
607225278,
1426881987,
1925078388,
2162078206,
2614888103,
3248222580,
3835390401,
4022224774,
264347078,
604807628,
770255983,
1249150122,
1555081692,
1996064986,
2554220882,
2821834349,
2952996808,
3210313671,
3336571891,
3584528711,
113926993,
338241895,
666307205,
773529912,
1294757372,
1396182291,
1695183700,
1986661051,
2177026350,
2456956037,
2730485921,
2820302411,
3259730800,
3345764771,
3516065817,
3600352804,
4094571909,
275423344,
430227734,
506948616,
659060556,
883997877,
958139571,
1322822218,
1537002063,
1747873779,
1955562222,
2024104815,
2227730452,
2361852424,
2428436474,
2756734187,
3204031479,
3329325298
)
state: Array(
1779033703,
3144134277,
1013904242,
2773480762,
1359893119,
2600822924,
528734635,
1541459225
)
message: Encoding.UTF8.encode("")
bytes.each((octet) => {
message.add(octet)
})
message.add(128)
remainder: message.size().mod(64)
zeroCount: 56 - remainder
(zeroCount < 0).ifTrue(() => {
zeroCount = zeroCount + 64
})
appendZeros: null
appendZeros = (remaining) => {
(remaining > 0).ifTrue(() => {
message.add(0)
appendZeros(remaining - 1)
})
}
appendZeros(zeroCount)
bitLength: originalSize * 8
lengthDivisors: Array(
72057594037927936,
281474976710656,
1099511627776,
4294967296,
16777216,
65536,
256,
1
)
lengthDivisors.each((divisor) => {
message.add(bitLength.div(divisor).mod(256))
})
processBlock: (blockOffset) => {
schedule: Array(...roundConstants)
scheduleIndex: 0
roundConstants.each((ignoredConstant) => {
(scheduleIndex < 16).ifTrue(() => {
offset: blockOffset + scheduleIndex * 4
value:
message[offset] * 16777216 +
message[offset + 1] * 65536 +
message[offset + 2] * 256 +
message[offset + 3]
schedule[scheduleIndex] = value
})
(scheduleIndex >= 16).ifTrue(() => {
value:
schedule[scheduleIndex - 16] +
lowerSigma0(schedule[scheduleIndex - 15]) +
schedule[scheduleIndex - 7] +
lowerSigma1(schedule[scheduleIndex - 2])
schedule[scheduleIndex] = word32(value)
})
scheduleIndex = scheduleIndex + 1
})
(a, b, c, d, e, f, g, h): state
roundIndex: 0
roundConstants.each((constant) => {
temporary1: word32(
h +
upperSigma1(e) +
choose(e, f, g) +
constant +
schedule[roundIndex]
)
temporary2: word32(
upperSigma0(a) +
majority(a, b, c)
)
h = g
g = f
f = e
e = word32(d + temporary1)
d = c
c = b
b = a
a = word32(temporary1 + temporary2)
roundIndex = roundIndex + 1
})
state[0] = word32(state[0] + a)
state[1] = word32(state[1] + b)
state[2] = word32(state[2] + c)
state[3] = word32(state[3] + d)
state[4] = word32(state[4] + e)
state[5] = word32(state[5] + f)
state[6] = word32(state[6] + g)
state[7] = word32(state[7] + h)
}
processBlocks: null
processBlocks = (start, end) => {
length: end - start
(length == 1).ifTrue(() => {
processBlock(start * 64)
})
(length > 1).ifTrue(() => {
middle: start + length.div(2)
processBlocks(start, middle)
processBlocks(middle, end)
})
}
processBlocks(0, message.size().div(64))
result: Encoding.UTF8.encode("")
state.each((value) => {
result.add(value.div(16777216).mod(256))
result.add(value.div(65536).mod(256))
result.add(value.div(256).mod(256))
result.add(value.mod(256))
})
result
}

← crypto family · Standard-library source