sha3: Avo port of keccakf_amd64.s
This implementation utilizes the same registers found in the reference
implementation, aiming to produce a minimal semantic diff between the
Avo-generated output and the original hand-written assembly.
To verify the Avo implementation, the reference and Avo-generated
assembly files are fed to `go tool asm`, capturing the debug output into
corresponding temp files. The debug output contains supplementary
metadata (line numbers, instruction offsets, and source file references)
that must be removed in order to obtain a semantic diff of the two
files. This is accomplished via a small utility script written in awk.
Commands used to verify Avo output:
BASE="d66d9c31b4ae80d173d1187a9e40c188788dbdbc"
go tool asm -o /dev/null -debug \
<(git cat-file -p "$BASE":sha3/keccakf_amd64.s) \
> /tmp/reference.s
go tool asm -o /dev/null -debug \
sha3/keccakf_amd64.s \
> /tmp/avo.s
normalize(){
awk '{
$1=$2=$3="";
print substr($0,4)
}'
}
diff <(normalize < /tmp/reference.s) <(normalize < /tmp/avo.s)
Change-Id: I1c0ea516531355263b83d3b66a37df090e293cea
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/594655
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Russell Webb <russell.webb@protonmail.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
This commit is contained in:
committed by
Gopher Robot
parent
80fd97208d
commit
e983fa2741
@@ -0,0 +1,15 @@
|
||||
module sha3/_asm
|
||||
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/mmcloughlin/avo v0.6.0
|
||||
golang.org/x/crypto v0.25.0
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.19.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/tools v0.23.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
|
||||
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
@@ -0,0 +1,438 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources at https://github.com/gvanas/KeccakCodePackage
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
. "github.com/mmcloughlin/avo/build"
|
||||
. "github.com/mmcloughlin/avo/operand"
|
||||
. "github.com/mmcloughlin/avo/reg"
|
||||
_ "golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
//go:generate go run . -out ../keccakf_amd64.s -pkg sha3
|
||||
|
||||
// Round Constants for use in the ι step.
|
||||
var RoundConstants = [24]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,
|
||||
}
|
||||
|
||||
var (
|
||||
// Temporary registers
|
||||
rT1 GPPhysical = RAX
|
||||
|
||||
// Round vars
|
||||
rpState = Mem{Base: RDI}
|
||||
rpStack = Mem{Base: RSP}
|
||||
|
||||
rDa = RBX
|
||||
rDe = RCX
|
||||
rDi = RDX
|
||||
rDo = R8
|
||||
rDu = R9
|
||||
|
||||
rBa = R10
|
||||
rBe = R11
|
||||
rBi = R12
|
||||
rBo = R13
|
||||
rBu = R14
|
||||
|
||||
rCa = RSI
|
||||
rCe = RBP
|
||||
rCi = rBi
|
||||
rCo = rBo
|
||||
rCu = R15
|
||||
)
|
||||
|
||||
const (
|
||||
_ba = iota * 8
|
||||
_be
|
||||
_bi
|
||||
_bo
|
||||
_bu
|
||||
_ga
|
||||
_ge
|
||||
_gi
|
||||
_go
|
||||
_gu
|
||||
_ka
|
||||
_ke
|
||||
_ki
|
||||
_ko
|
||||
_ku
|
||||
_ma
|
||||
_me
|
||||
_mi
|
||||
_mo
|
||||
_mu
|
||||
_sa
|
||||
_se
|
||||
_si
|
||||
_so
|
||||
_su
|
||||
)
|
||||
|
||||
func main() {
|
||||
Package("golang.org/x/crypto/sha3")
|
||||
ConstraintExpr("amd64,!purego,gc")
|
||||
keccakF1600()
|
||||
Generate()
|
||||
}
|
||||
|
||||
func MOVQ_RBI_RCE() { MOVQ(rBi, rCe) }
|
||||
func XORQ_RT1_RCA() { XORQ(rT1, rCa) }
|
||||
func XORQ_RT1_RCE() { XORQ(rT1, rCe) }
|
||||
func XORQ_RBA_RCU() { XORQ(rBa, rCu) }
|
||||
func XORQ_RBE_RCU() { XORQ(rBe, rCu) }
|
||||
func XORQ_RDU_RCU() { XORQ(rDu, rCu) }
|
||||
func XORQ_RDA_RCA() { XORQ(rDa, rCa) }
|
||||
func XORQ_RDE_RCE() { XORQ(rDe, rCe) }
|
||||
|
||||
type ArgMacro func()
|
||||
|
||||
func mKeccakRound(
|
||||
iState, oState Mem,
|
||||
rc U64,
|
||||
B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU,
|
||||
K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA,
|
||||
M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA,
|
||||
S_RDE_RCE ArgMacro,
|
||||
) {
|
||||
Comment("Prepare round")
|
||||
MOVQ(rCe, rDa)
|
||||
ROLQ(Imm(1), rDa)
|
||||
|
||||
MOVQ(iState.Offset(_bi), rCi)
|
||||
XORQ(iState.Offset(_gi), rDi)
|
||||
XORQ(rCu, rDa)
|
||||
XORQ(iState.Offset(_ki), rCi)
|
||||
XORQ(iState.Offset(_mi), rDi)
|
||||
XORQ(rDi, rCi)
|
||||
|
||||
MOVQ(rCi, rDe)
|
||||
ROLQ(Imm(1), rDe)
|
||||
|
||||
MOVQ(iState.Offset(_bo), rCo)
|
||||
XORQ(iState.Offset(_go), rDo)
|
||||
XORQ(rCa, rDe)
|
||||
XORQ(iState.Offset(_ko), rCo)
|
||||
XORQ(iState.Offset(_mo), rDo)
|
||||
XORQ(rDo, rCo)
|
||||
|
||||
MOVQ(rCo, rDi)
|
||||
ROLQ(Imm(1), rDi)
|
||||
|
||||
MOVQ(rCu, rDo)
|
||||
XORQ(rCe, rDi)
|
||||
ROLQ(Imm(1), rDo)
|
||||
|
||||
MOVQ(rCa, rDu)
|
||||
XORQ(rCi, rDo)
|
||||
ROLQ(Imm(1), rDu)
|
||||
|
||||
Comment("Result b")
|
||||
MOVQ(iState.Offset(_ba), rBa)
|
||||
MOVQ(iState.Offset(_ge), rBe)
|
||||
XORQ(rCo, rDu)
|
||||
MOVQ(iState.Offset(_ki), rBi)
|
||||
MOVQ(iState.Offset(_mo), rBo)
|
||||
MOVQ(iState.Offset(_su), rBu)
|
||||
XORQ(rDe, rBe)
|
||||
ROLQ(Imm(44), rBe)
|
||||
XORQ(rDi, rBi)
|
||||
XORQ(rDa, rBa)
|
||||
ROLQ(Imm(43), rBi)
|
||||
|
||||
MOVQ(rBe, rCa)
|
||||
MOVQ(rc, rT1)
|
||||
ORQ(rBi, rCa)
|
||||
XORQ(rBa, rT1)
|
||||
XORQ(rT1, rCa)
|
||||
MOVQ(rCa, oState.Offset(_ba))
|
||||
|
||||
XORQ(rDu, rBu)
|
||||
ROLQ(Imm(14), rBu)
|
||||
MOVQ(rBa, rCu)
|
||||
ANDQ(rBe, rCu)
|
||||
XORQ(rBu, rCu)
|
||||
MOVQ(rCu, oState.Offset(_bu))
|
||||
|
||||
XORQ(rDo, rBo)
|
||||
ROLQ(Imm(21), rBo)
|
||||
MOVQ(rBo, rT1)
|
||||
ANDQ(rBu, rT1)
|
||||
XORQ(rBi, rT1)
|
||||
MOVQ(rT1, oState.Offset(_bi))
|
||||
|
||||
NOTQ(rBi)
|
||||
ORQ(rBa, rBu)
|
||||
ORQ(rBo, rBi)
|
||||
XORQ(rBo, rBu)
|
||||
XORQ(rBe, rBi)
|
||||
MOVQ(rBu, oState.Offset(_bo))
|
||||
MOVQ(rBi, oState.Offset(_be))
|
||||
B_RBI_RCE()
|
||||
|
||||
Comment("Result g")
|
||||
MOVQ(iState.Offset(_gu), rBe)
|
||||
XORQ(rDu, rBe)
|
||||
MOVQ(iState.Offset(_ka), rBi)
|
||||
ROLQ(Imm(20), rBe)
|
||||
XORQ(rDa, rBi)
|
||||
ROLQ(Imm(3), rBi)
|
||||
MOVQ(iState.Offset(_bo), rBa)
|
||||
MOVQ(rBe, rT1)
|
||||
ORQ(rBi, rT1)
|
||||
XORQ(rDo, rBa)
|
||||
MOVQ(iState.Offset(_me), rBo)
|
||||
MOVQ(iState.Offset(_si), rBu)
|
||||
ROLQ(Imm(28), rBa)
|
||||
XORQ(rBa, rT1)
|
||||
MOVQ(rT1, oState.Offset(_ga))
|
||||
G_RT1_RCA()
|
||||
|
||||
XORQ(rDe, rBo)
|
||||
ROLQ(Imm(45), rBo)
|
||||
MOVQ(rBi, rT1)
|
||||
ANDQ(rBo, rT1)
|
||||
XORQ(rBe, rT1)
|
||||
MOVQ(rT1, oState.Offset(_ge))
|
||||
G_RT1_RCE()
|
||||
|
||||
XORQ(rDi, rBu)
|
||||
ROLQ(Imm(61), rBu)
|
||||
MOVQ(rBu, rT1)
|
||||
ORQ(rBa, rT1)
|
||||
XORQ(rBo, rT1)
|
||||
MOVQ(rT1, oState.Offset(_go))
|
||||
|
||||
ANDQ(rBe, rBa)
|
||||
XORQ(rBu, rBa)
|
||||
MOVQ(rBa, oState.Offset(_gu))
|
||||
NOTQ(rBu)
|
||||
G_RBA_RCU()
|
||||
|
||||
ORQ(rBu, rBo)
|
||||
XORQ(rBi, rBo)
|
||||
MOVQ(rBo, oState.Offset(_gi))
|
||||
|
||||
Comment("Result k")
|
||||
MOVQ(iState.Offset(_be), rBa)
|
||||
MOVQ(iState.Offset(_gi), rBe)
|
||||
MOVQ(iState.Offset(_ko), rBi)
|
||||
MOVQ(iState.Offset(_mu), rBo)
|
||||
MOVQ(iState.Offset(_sa), rBu)
|
||||
XORQ(rDi, rBe)
|
||||
ROLQ(Imm(6), rBe)
|
||||
XORQ(rDo, rBi)
|
||||
ROLQ(Imm(25), rBi)
|
||||
MOVQ(rBe, rT1)
|
||||
ORQ(rBi, rT1)
|
||||
XORQ(rDe, rBa)
|
||||
ROLQ(Imm(1), rBa)
|
||||
XORQ(rBa, rT1)
|
||||
MOVQ(rT1, oState.Offset(_ka))
|
||||
K_RT1_RCA()
|
||||
|
||||
XORQ(rDu, rBo)
|
||||
ROLQ(Imm(8), rBo)
|
||||
MOVQ(rBi, rT1)
|
||||
ANDQ(rBo, rT1)
|
||||
XORQ(rBe, rT1)
|
||||
MOVQ(rT1, oState.Offset(_ke))
|
||||
K_RT1_RCE()
|
||||
|
||||
XORQ(rDa, rBu)
|
||||
ROLQ(Imm(18), rBu)
|
||||
NOTQ(rBo)
|
||||
MOVQ(rBo, rT1)
|
||||
ANDQ(rBu, rT1)
|
||||
XORQ(rBi, rT1)
|
||||
MOVQ(rT1, oState.Offset(_ki))
|
||||
|
||||
MOVQ(rBu, rT1)
|
||||
ORQ(rBa, rT1)
|
||||
XORQ(rBo, rT1)
|
||||
MOVQ(rT1, oState.Offset(_ko))
|
||||
|
||||
ANDQ(rBe, rBa)
|
||||
XORQ(rBu, rBa)
|
||||
MOVQ(rBa, oState.Offset(_ku))
|
||||
K_RBA_RCU()
|
||||
|
||||
Comment("Result m")
|
||||
MOVQ(iState.Offset(_ga), rBe)
|
||||
XORQ(rDa, rBe)
|
||||
MOVQ(iState.Offset(_ke), rBi)
|
||||
ROLQ(Imm(36), rBe)
|
||||
XORQ(rDe, rBi)
|
||||
MOVQ(iState.Offset(_bu), rBa)
|
||||
ROLQ(Imm(10), rBi)
|
||||
MOVQ(rBe, rT1)
|
||||
MOVQ(iState.Offset(_mi), rBo)
|
||||
ANDQ(rBi, rT1)
|
||||
XORQ(rDu, rBa)
|
||||
MOVQ(iState.Offset(_so), rBu)
|
||||
ROLQ(Imm(27), rBa)
|
||||
XORQ(rBa, rT1)
|
||||
MOVQ(rT1, oState.Offset(_ma))
|
||||
M_RT1_RCA()
|
||||
|
||||
XORQ(rDi, rBo)
|
||||
ROLQ(Imm(15), rBo)
|
||||
MOVQ(rBi, rT1)
|
||||
ORQ(rBo, rT1)
|
||||
XORQ(rBe, rT1)
|
||||
MOVQ(rT1, oState.Offset(_me))
|
||||
M_RT1_RCE()
|
||||
|
||||
XORQ(rDo, rBu)
|
||||
ROLQ(Imm(56), rBu)
|
||||
NOTQ(rBo)
|
||||
MOVQ(rBo, rT1)
|
||||
ORQ(rBu, rT1)
|
||||
XORQ(rBi, rT1)
|
||||
MOVQ(rT1, oState.Offset(_mi))
|
||||
|
||||
ORQ(rBa, rBe)
|
||||
XORQ(rBu, rBe)
|
||||
MOVQ(rBe, oState.Offset(_mu))
|
||||
|
||||
ANDQ(rBa, rBu)
|
||||
XORQ(rBo, rBu)
|
||||
MOVQ(rBu, oState.Offset(_mo))
|
||||
M_RBE_RCU()
|
||||
|
||||
Comment("Result s")
|
||||
MOVQ(iState.Offset(_bi), rBa)
|
||||
MOVQ(iState.Offset(_go), rBe)
|
||||
MOVQ(iState.Offset(_ku), rBi)
|
||||
XORQ(rDi, rBa)
|
||||
MOVQ(iState.Offset(_ma), rBo)
|
||||
ROLQ(Imm(62), rBa)
|
||||
XORQ(rDo, rBe)
|
||||
MOVQ(iState.Offset(_se), rBu)
|
||||
ROLQ(Imm(55), rBe)
|
||||
|
||||
XORQ(rDu, rBi)
|
||||
MOVQ(rBa, rDu)
|
||||
XORQ(rDe, rBu)
|
||||
ROLQ(Imm(2), rBu)
|
||||
ANDQ(rBe, rDu)
|
||||
XORQ(rBu, rDu)
|
||||
MOVQ(rDu, oState.Offset(_su))
|
||||
|
||||
ROLQ(Imm(39), rBi)
|
||||
S_RDU_RCU()
|
||||
NOTQ(rBe)
|
||||
XORQ(rDa, rBo)
|
||||
MOVQ(rBe, rDa)
|
||||
ANDQ(rBi, rDa)
|
||||
XORQ(rBa, rDa)
|
||||
MOVQ(rDa, oState.Offset(_sa))
|
||||
S_RDA_RCA()
|
||||
|
||||
ROLQ(Imm(41), rBo)
|
||||
MOVQ(rBi, rDe)
|
||||
ORQ(rBo, rDe)
|
||||
XORQ(rBe, rDe)
|
||||
MOVQ(rDe, oState.Offset(_se))
|
||||
S_RDE_RCE()
|
||||
|
||||
MOVQ(rBo, rDi)
|
||||
MOVQ(rBu, rDo)
|
||||
ANDQ(rBu, rDi)
|
||||
ORQ(rBa, rDo)
|
||||
XORQ(rBi, rDi)
|
||||
XORQ(rBo, rDo)
|
||||
MOVQ(rDi, oState.Offset(_si))
|
||||
MOVQ(rDo, oState.Offset(_so))
|
||||
}
|
||||
|
||||
// keccakF1600 applies the Keccak permutation to a 1600b-wide
|
||||
// state represented as a slice of 25 uint64s.
|
||||
func keccakF1600() {
|
||||
Implement("keccakF1600")
|
||||
AllocLocal(200)
|
||||
|
||||
Load(Param("a"), rpState.Base)
|
||||
|
||||
Comment("Convert the user state into an internal state")
|
||||
NOTQ(rpState.Offset(_be))
|
||||
NOTQ(rpState.Offset(_bi))
|
||||
NOTQ(rpState.Offset(_go))
|
||||
NOTQ(rpState.Offset(_ki))
|
||||
NOTQ(rpState.Offset(_mi))
|
||||
NOTQ(rpState.Offset(_sa))
|
||||
|
||||
Comment("Execute the KeccakF permutation")
|
||||
MOVQ(rpState.Offset(_ba), rCa)
|
||||
MOVQ(rpState.Offset(_be), rCe)
|
||||
MOVQ(rpState.Offset(_bu), rCu)
|
||||
|
||||
XORQ(rpState.Offset(_ga), rCa)
|
||||
XORQ(rpState.Offset(_ge), rCe)
|
||||
XORQ(rpState.Offset(_gu), rCu)
|
||||
|
||||
XORQ(rpState.Offset(_ka), rCa)
|
||||
XORQ(rpState.Offset(_ke), rCe)
|
||||
XORQ(rpState.Offset(_ku), rCu)
|
||||
|
||||
XORQ(rpState.Offset(_ma), rCa)
|
||||
XORQ(rpState.Offset(_me), rCe)
|
||||
XORQ(rpState.Offset(_mu), rCu)
|
||||
|
||||
XORQ(rpState.Offset(_sa), rCa)
|
||||
XORQ(rpState.Offset(_se), rCe)
|
||||
MOVQ(rpState.Offset(_si), rDi)
|
||||
MOVQ(rpState.Offset(_so), rDo)
|
||||
XORQ(rpState.Offset(_su), rCu)
|
||||
|
||||
for i, rc := range RoundConstants[:len(RoundConstants)-1] {
|
||||
var iState, oState Mem
|
||||
if i%2 == 0 {
|
||||
iState, oState = rpState, rpStack
|
||||
} else {
|
||||
iState, oState = rpStack, rpState
|
||||
}
|
||||
mKeccakRound(iState, oState, U64(rc), MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE)
|
||||
}
|
||||
mKeccakRound(rpStack, rpState, U64(RoundConstants[len(RoundConstants)-1]), NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP)
|
||||
|
||||
Comment("Revert the internal state to the user state")
|
||||
NOTQ(rpState.Offset(_be))
|
||||
NOTQ(rpState.Offset(_bi))
|
||||
NOTQ(rpState.Offset(_go))
|
||||
NOTQ(rpState.Offset(_ki))
|
||||
NOTQ(rpState.Offset(_mi))
|
||||
NOTQ(rpState.Offset(_sa))
|
||||
|
||||
RET()
|
||||
}
|
||||
+5403
-374
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user