blob: fa99d5a82a6db7476231235776f990f31a38a78a [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
//
// sha3.swift - Implementation of SHA3
//
// Created by Michael Scott on 7/08/2017.
//
import Foundation
public struct SHA3{
private var length:UInt64
private var rate:Int
private var len:Int
private var s=[[UInt64]](repeating:[UInt64](repeating:0,count:5),count:5)
static let RC:[UInt64]=[
0x0000000000000001,0x0000000000008082,0x800000000000808A,0x8000000080008000,
0x000000000000808B,0x0000000080000001,0x8000000080008081,0x8000000000008009,
0x000000000000008A,0x0000000000000088,0x0000000080008009,0x000000008000000A,
0x000000008000808B,0x800000000000008B,0x8000000000008089,0x8000000000008003,
0x8000000000008002,0x8000000000000080,0x000000000000800A,0x800000008000000A,
0x8000000080008081,0x8000000000008080,0x0000000080000001,0x8000000080008008]
static let HASH224:Int=28
static let HASH256:Int=32
static let HASH384:Int=48
static let HASH512:Int=64
static let SHAKE128:Int=16
static let SHAKE256:Int=32
static let ROUNDS:Int=24
private static func rotl(_ x: UInt64,_ n: UInt32) -> UInt64
{
return ((x<<UInt64(n))|(x>>(64-UInt64(n))))
}
private mutating func transform()
{ /* basic transformation step */
var c=[UInt64](repeating:0,count:5)
var d=[UInt64](repeating:0,count:5)
var b=[[UInt64]](repeating:[UInt64](repeating:0,count:5),count:5)
for k in 0 ..< SHA3.ROUNDS
{
c[0]=s[0][0]^s[0][1]^s[0][2]^s[0][3]^s[0][4]
c[1]=s[1][0]^s[1][1]^s[1][2]^s[1][3]^s[1][4]
c[2]=s[2][0]^s[2][1]^s[2][2]^s[2][3]^s[2][4]
c[3]=s[3][0]^s[3][1]^s[3][2]^s[3][3]^s[3][4]
c[4]=s[4][0]^s[4][1]^s[4][2]^s[4][3]^s[4][4]
d[0]=c[4]^SHA3.rotl(c[1],1)
d[1]=c[0]^SHA3.rotl(c[2],1)
d[2]=c[1]^SHA3.rotl(c[3],1)
d[3]=c[2]^SHA3.rotl(c[4],1)
d[4]=c[3]^SHA3.rotl(c[0],1)
for i in 0 ..< 5 {
for j in 0 ..< 5 {
s[i][j]^=d[i]
}
}
b[0][0]=s[0][0]
b[1][3]=SHA3.rotl(s[0][1],36)
b[2][1]=SHA3.rotl(s[0][2],3)
b[3][4]=SHA3.rotl(s[0][3],41)
b[4][2]=SHA3.rotl(s[0][4],18)
b[0][2]=SHA3.rotl(s[1][0],1)
b[1][0]=SHA3.rotl(s[1][1],44)
b[2][3]=SHA3.rotl(s[1][2],10)
b[3][1]=SHA3.rotl(s[1][3],45)
b[4][4]=SHA3.rotl(s[1][4],2)
b[0][4]=SHA3.rotl(s[2][0],62)
b[1][2]=SHA3.rotl(s[2][1],6)
b[2][0]=SHA3.rotl(s[2][2],43)
b[3][3]=SHA3.rotl(s[2][3],15)
b[4][1]=SHA3.rotl(s[2][4],61)
b[0][1]=SHA3.rotl(s[3][0],28)
b[1][4]=SHA3.rotl(s[3][1],55)
b[2][2]=SHA3.rotl(s[3][2],25)
b[3][0]=SHA3.rotl(s[3][3],21)
b[4][3]=SHA3.rotl(s[3][4],56)
b[0][3]=SHA3.rotl(s[4][0],27)
b[1][1]=SHA3.rotl(s[4][1],20)
b[2][4]=SHA3.rotl(s[4][2],39)
b[3][2]=SHA3.rotl(s[4][3],8)
b[4][0]=SHA3.rotl(s[4][4],14)
for i in 0 ..< 5 {
for j in 0 ..< 5 {
s[i][j]=b[i][j]^(~b[(i+1)%5][j]&b[(i+2)%5][j])
}
}
s[0][0]^=SHA3.RC[k]
}
}
/* Re-Initialise Hash function */
mutating func init_it(_ olen: Int)
{ /* initialise */
len=olen
rate=200-2*olen
}
public init(_ olen: Int)
{
for i in 0 ..< 5 {
for j in 0..<5 {
s[i][j]=0
}
}
length=0
len=0
rate=0
init_it(olen)
}
/* process a single byte */
public mutating func process(_ byt: UInt8)
{ /* process the next message byte */
let cnt=Int(length%UInt64(rate))
let b=cnt%8
let ind=cnt/8
let i=ind%5
let j=ind/5
s[i][j]^=(UInt64(byt)&0xff)<<UInt64(8*b)
length+=1
if cnt+1 == rate {transform()}
}
public mutating func squeeze(_ buff:inout [UInt8],_ olen: Int)
{
var done=false
var m: Int = 0
/* extract by columns */
while true {
for j in 0 ..< 5 {
for i in 0 ..< 5
{
var el=s[i][j]
for _ in 0 ..< 8
{
buff[m]=UInt8(el&0xff)
m+=1
if m>=olen || (m%rate)==0 {
done=true
break
}
el>>=8
}
if done {break}
}
if done {break}
}
if m>=olen {break}
done=false
transform()
}
}
/* Generate Hash */
public mutating func hash(_ digest:inout [UInt8])
{ /* pad message and finish - supply digest */
let q=rate-Int(length%UInt64(rate))
if q==1 {process(0x86)}
else {
process(0x06)
while Int(length%UInt64(rate)) != rate-1 {process(0x00)}
process(0x80)
}
squeeze(&digest,len)
}
public mutating func shake(_ digest:inout [UInt8],_ olen: Int)
{
let q=rate-Int(length%UInt64(rate))
if q==1 {process(0x9f)}
else {
process(0x1f)
while Int(length%UInt64(rate)) != rate-1 {process(0x00)}
process(0x80)
}
squeeze(&digest,olen)
}
}
//916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18
//afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185
//98be04516c04cc73593fef3ed0352ea9f6443942d6950e29a372a681c3deaf4535423709b02843948684e029010badcc0acd8303fc85fdad3eabf4f78cae165635f57afd28810fc2
/*
public func TestSHA3()
{
let test=String("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")
var digest=[UInt8](repeating: 0,count: 172)
let t=[UInt8]( (test!).utf8)
var sh=SHA3(SHA3.HASH256)
for i in 0..<t.count {
sh.process(t[i])
}
sh.hash(&digest)
for i in 0 ..< 32
{
let h=String(digest[i],radix:16)
print("\(h)", terminator: "")
}
print("")
sh=SHA3(SHA3.HASH512)
for i in 0..<t.count {
sh.process(t[i])
}
sh.hash(&digest)
for i in 0 ..< 64
{
let h=String(digest[i],radix:16)
print("\(h)", terminator: "")
}
print("")
sh=SHA3(SHA3.SHAKE256)
for i in 0..<t.count {
sh.process(t[i])
}
sh.shake(&digest,72)
for i in 0 ..< 72
{
let h=String(digest[i],radix:16)
print("\(h)", terminator: "")
}
print("")
}
TestSHA3() */