blob: 9188b6b074a433775405acbb0e8b7047285e24eb [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 public let HASH224:Int=28
static public let HASH256:Int=32
static public let HASH384:Int=48
static public let HASH512:Int=64
static public let SHAKE128:Int=16
static public 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() */