mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-27 04:36:19 +08:00
zuc: eea seek benchmark test and refactor
This commit is contained in:
parent
865159d86a
commit
90fa2233a8
62
zuc/eea.go
62
zuc/eea.go
@ -8,9 +8,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// number of words in a round
|
||||||
RoundWords = 32
|
RoundWords = 32
|
||||||
WordSize = 4
|
// number of bytes in a word
|
||||||
WordMask = WordSize - 1
|
WordSize = 4
|
||||||
|
WordMask = WordSize - 1
|
||||||
|
// number of bytes in a round
|
||||||
RoundBytes = RoundWords * WordSize
|
RoundBytes = RoundWords * WordSize
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,8 +21,8 @@ type eea struct {
|
|||||||
zucState32
|
zucState32
|
||||||
x [WordSize]byte // remaining bytes buffer
|
x [WordSize]byte // remaining bytes buffer
|
||||||
xLen int // number of remaining bytes
|
xLen int // number of remaining bytes
|
||||||
initState zucState32
|
initState zucState32 // initial state for reset
|
||||||
used uint64
|
used uint64 // number of key bytes processed, current offset
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCipher create a stream cipher based on key and iv aguments.
|
// NewCipher create a stream cipher based on key and iv aguments.
|
||||||
@ -105,61 +108,60 @@ func (c *eea) reset() {
|
|||||||
c.used = 0
|
c.used = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *eea) XORKeyStreamAt(dst, src []byte, offset uint64) {
|
// seek sets the offset for the next XORKeyStream operation.
|
||||||
if len(dst) < len(src) {
|
//
|
||||||
panic("zuc: output smaller than input")
|
// If the offset is less than the current offset, the state will be reset to the initial state.
|
||||||
}
|
// If the offset is equal to the current offset, the function behaves the same as XORKeyStream.
|
||||||
if alias.InexactOverlap(dst[:len(src)], src) {
|
// If the offset is greater than the current offset, the function will forward the state to the offset.
|
||||||
panic("zuc: invalid buffer overlap")
|
// Note: This method is not thread-safe.
|
||||||
}
|
func (c *eea) seek(offset uint64) {
|
||||||
if offset < c.used {
|
if offset < c.used {
|
||||||
// reset the state to the initial state
|
|
||||||
c.reset()
|
c.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
if offset == c.used {
|
if offset == c.used {
|
||||||
c.XORKeyStream(dst, src)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
gap := offset - c.used
|
||||||
offsetDiff := offset - c.used
|
if gap <= uint64(c.xLen) {
|
||||||
if offsetDiff <= uint64(c.xLen) {
|
// offset is within the remaining key bytes
|
||||||
c.xLen -= int(offsetDiff)
|
c.xLen -= int(gap)
|
||||||
c.used += offsetDiff
|
c.used += gap
|
||||||
if c.xLen > 0 {
|
if c.xLen > 0 {
|
||||||
copy(c.x[:], c.x[offsetDiff:])
|
// adjust remaining key bytes
|
||||||
|
copy(c.x[:], c.x[gap:])
|
||||||
}
|
}
|
||||||
c.XORKeyStream(dst, src)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// consumed all remaining key bytes first
|
// consumed all remaining key bytes first
|
||||||
if c.xLen > 0 {
|
if c.xLen > 0 {
|
||||||
c.used += uint64(c.xLen)
|
c.used += uint64(c.xLen)
|
||||||
offsetDiff -= uint64(c.xLen)
|
gap -= uint64(c.xLen)
|
||||||
c.xLen = 0
|
c.xLen = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward the state to the offset
|
// forward the state to the offset
|
||||||
|
c.used += gap
|
||||||
stepLen := uint64(RoundBytes)
|
stepLen := uint64(RoundBytes)
|
||||||
var keyStream [RoundWords]uint32
|
var keyStream [RoundWords]uint32
|
||||||
for ; offsetDiff >= uint64(stepLen); offsetDiff -= stepLen {
|
for gap >= stepLen {
|
||||||
genKeyStream(keyStream[:], &c.zucState32)
|
genKeyStream(keyStream[:], &c.zucState32)
|
||||||
c.used += stepLen
|
gap -= stepLen
|
||||||
}
|
}
|
||||||
|
|
||||||
if offsetDiff > 0 {
|
if gap > 0 {
|
||||||
numWords := (offsetDiff + WordMask) / WordSize
|
numWords := (gap + WordMask) / WordSize
|
||||||
genKeyStream(keyStream[:numWords], &c.zucState32)
|
genKeyStream(keyStream[:numWords], &c.zucState32)
|
||||||
partiallyUsed := int(offsetDiff & WordMask)
|
partiallyUsed := int(gap & WordMask)
|
||||||
c.used += numWords * WordSize
|
|
||||||
if partiallyUsed > 0 {
|
if partiallyUsed > 0 {
|
||||||
// save remaining key bytes (less than 4 bytes)
|
// save remaining key bytes (less than 4 bytes)
|
||||||
c.xLen = WordSize - partiallyUsed
|
c.xLen = WordSize - partiallyUsed
|
||||||
c.used -= uint64(c.xLen)
|
|
||||||
byteorder.BEPutUint32(c.x[:], keyStream[numWords-1])
|
byteorder.BEPutUint32(c.x[:], keyStream[numWords-1])
|
||||||
copy(c.x[:], c.x[partiallyUsed:])
|
copy(c.x[:], c.x[partiallyUsed:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *eea) XORKeyStreamAt(dst, src []byte, offset uint64) {
|
||||||
|
c.seek(offset)
|
||||||
c.XORKeyStream(dst, src)
|
c.XORKeyStream(dst, src)
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ func TestXORStreamAt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Jump and forward (incomplete word)", func(t *testing.T) {
|
t.Run("Jump and forward (incomplete word): gap > xLen", func(t *testing.T) {
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
c.XORKeyStreamAt(dst[i:16], src[i:16], uint64(i))
|
c.XORKeyStreamAt(dst[i:16], src[i:16], uint64(i))
|
||||||
c.XORKeyStreamAt(dst[32:64], src[32:64], 32)
|
c.XORKeyStreamAt(dst[32:64], src[32:64], 32)
|
||||||
@ -122,7 +122,7 @@ func TestXORStreamAt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Jump and forward (incomplete word): offsetDiff <= xLen", func(t *testing.T) {
|
t.Run("Jump and forward (incomplete word): gap <= xLen", func(t *testing.T) {
|
||||||
c.XORKeyStreamAt(dst[:1], src[:1], 0)
|
c.XORKeyStreamAt(dst[:1], src[:1], 0)
|
||||||
c.XORKeyStreamAt(dst[3:16], src[3:16], 3)
|
c.XORKeyStreamAt(dst[3:16], src[3:16], 3)
|
||||||
if !bytes.Equal(dst[3:16], expected[3:16]) {
|
if !bytes.Equal(dst[3:16], expected[3:16]) {
|
||||||
@ -227,3 +227,33 @@ func BenchmarkEncrypt1K(b *testing.B) {
|
|||||||
func BenchmarkEncrypt8K(b *testing.B) {
|
func BenchmarkEncrypt8K(b *testing.B) {
|
||||||
benchmarkStream(b, make([]byte, almost8K))
|
benchmarkStream(b, make([]byte, almost8K))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func benchmarkSeek(b *testing.B, offset uint64) {
|
||||||
|
var key [16]byte
|
||||||
|
var iv [16]byte
|
||||||
|
|
||||||
|
stream, _ := NewCipher(key[:], iv[:])
|
||||||
|
|
||||||
|
eea, ok := stream.(*eea)
|
||||||
|
if !ok {
|
||||||
|
b.Fatal("not an eea")
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
eea.reset()
|
||||||
|
eea.seek(offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSeek1K(b *testing.B) {
|
||||||
|
benchmarkSeek(b, 1024)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSeek8K(b *testing.B) {
|
||||||
|
benchmarkSeek(b, 8*1024)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSeek1M(b *testing.B) {
|
||||||
|
benchmarkSeek(b, 1024*1024)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user