sm4: ppc64x, gcm with EncryptBlocks

This commit is contained in:
Sun Yimin 2024-09-13 14:32:04 +08:00 committed by GitHub
parent 78d55a69bc
commit e8d1100481
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -94,40 +94,53 @@ func (g *gcmAsm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) {
} }
} }
// counterCrypt encrypts in using AES in counter mode and places the result const fourBlocksSize = 64
const eightBlocksSize = fourBlocksSize * 2
// counterCrypt encrypts in using SM4 in counter mode and places the result
// into out. counter is the initial count value and will be updated with the next // into out. counter is the initial count value and will be updated with the next
// count value. The length of out must be greater than or equal to the length // count value. The length of out must be greater than or equal to the length
// of in. // of in.
// counterCryptASM implements counterCrypt which then allows the loop to
// be unrolled and optimized.
func (g *gcmAsm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) { func (g *gcmAsm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
var mask [gcmBlockSize]byte var mask [eightBlocksSize]byte
var counters [eightBlocksSize]byte
for len(in) >= gcmBlockSize { for len(in) >= eightBlocksSize {
// Hint to avoid bounds check for i := 0; i < 8; i++ {
_, _ = in[15], out[15] copy(counters[i*gcmBlockSize:(i+1)*gcmBlockSize], counter[:])
g.cipher.Encrypt(mask[:], counter[:]) gcmInc32(counter)
gcmInc32(counter) }
g.cipher.EncryptBlocks(mask[:], counters[:])
subtle.XORBytes(out, in, mask[:])
out = out[eightBlocksSize:]
in = in[eightBlocksSize:]
}
// XOR 16 bytes each loop iteration in 8 byte chunks if len(in) >= fourBlocksSize {
in0 := binary.LittleEndian.Uint64(in[0:]) for i := 0; i < 4; i++ {
in1 := binary.LittleEndian.Uint64(in[8:]) copy(counters[i*gcmBlockSize:(i+1)*gcmBlockSize], counter[:])
m0 := binary.LittleEndian.Uint64(mask[:8]) gcmInc32(counter)
m1 := binary.LittleEndian.Uint64(mask[8:]) }
binary.LittleEndian.PutUint64(out[:8], in0^m0) g.cipher.EncryptBlocks(mask[:], counters[:])
binary.LittleEndian.PutUint64(out[8:], in1^m1) subtle.XORBytes(out, in, mask[:fourBlocksSize])
out = out[16:] out = out[fourBlocksSize:]
in = in[16:] in = in[fourBlocksSize:]
} }
if len(in) > 0 { if len(in) > 0 {
g.cipher.Encrypt(mask[:], counter[:]) blocks := (len(in) + gcmBlockSize - 1) / gcmBlockSize
gcmInc32(counter) if blocks > 1 {
// XOR leftover bytes for i := 0; i < blocks; i++ {
for i, inb := range in { copy(counters[i*gcmBlockSize:], counter[:])
out[i] = inb ^ mask[i] gcmInc32(counter)
}
g.cipher.EncryptBlocks(mask[:], counters[:])
} else {
g.cipher.Encrypt(mask[:], counter[:])
gcmInc32(counter)
} }
} subtle.XORBytes(out, in, mask[:blocks*gcmBlockSize])
}
} }
// increments the rightmost 32-bits of the count value by 1. // increments the rightmost 32-bits of the count value by 1.
@ -160,11 +173,7 @@ func (g *gcmAsm) auth(out, ciphertext, aad []byte, tagMask *[gcmTagSize]byte) {
g.paddedGHASH(&hash, ciphertext) g.paddedGHASH(&hash, ciphertext)
lens := gcmLengths(uint64(len(aad))*8, uint64(len(ciphertext))*8) lens := gcmLengths(uint64(len(aad))*8, uint64(len(ciphertext))*8)
g.paddedGHASH(&hash, lens[:]) g.paddedGHASH(&hash, lens[:])
subtle.XORBytes(out, hash[:], tagMask[:])
copy(out, hash[:])
for i := range out {
out[i] ^= tagMask[i]
}
} }
// Seal encrypts and authenticates plaintext. See the [cipher.AEAD] interface for // Seal encrypts and authenticates plaintext. See the [cipher.AEAD] interface for
@ -228,7 +237,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
// clear(out) // clear(out)
for i := range out { for i := range out {
out[i] = 0 out[i] = 0
} }
return nil, errOpen return nil, errOpen
} }