-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaes_prf.go
More file actions
82 lines (74 loc) · 2.92 KB
/
Copy pathaes_prf.go
File metadata and controls
82 lines (74 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package aes
// AESPRF implements the AES-PRF construction with 4 rounds before feed-forward
// and 6 rounds after feed-forward (5 full + 1 final).
//
// The construction is:
// 1. Apply initial AddRoundKey with round key 0
// 2. Apply 4 full AES rounds (SubBytes, ShiftRows, MixColumns, AddRoundKey)
// 3. XOR the result with the original input (feed-forward)
// 4. Apply 5 full AES rounds (SubBytes, ShiftRows, MixColumns, AddRoundKey)
// 5. Apply final round (SubBytes, ShiftRows, AddRoundKey, no MixColumns)
//
// This construction provides a pseudorandom function (PRF) based on the AES round function.
// The feed-forward XOR adds non-linearity that makes the construction particularly suitable
// for use in cryptographic hash functions, MACs, and key derivation.
//
// Performance: ~152 ns/op with zero allocations on Apple M4 ARM64.
// Hardware acceleration (Intel AES-NI, ARM Crypto) is automatically used when available.
type AESPRF struct {
ks *KeySchedule
}
// NewAESPRF creates a new AES-PRF instance with the given key.
// The key must be 16, 24, or 32 bytes for AES-128, AES-192, or AES-256 respectively.
//
// For AES-PRF, we use a 10-round structure regardless of key size:
// - 1 initial AddRoundKey
// - 4 full rounds
// - XOR feed-forward
// - 5 full rounds
// - 1 final round (no MixColumns)
//
// This gives us a total of 10 rounds, matching AES-128 structure.
func NewAESPRF(key []byte) (*AESPRF, error) {
// Create key schedule - we'll use AES-128 structure (10 rounds)
ks, err := NewKeySchedule(key)
if err != nil {
return nil, err
}
return &AESPRF{ks: ks}, nil
}
// PRF applies the AES-PRF construction to the input block.
// The input block is modified in place to contain the output.
//
// The construction:
// 1. state = AddRoundKey(input, roundKey[0])
// 2. 4 full AES rounds using Rounds4HW (roundKeys[1-4])
// 3. state = state ⊕ input (feed-forward)
// 4. 5 full rounds + 1 final round using Rounds6WithFinalHW (roundKeys[5-10])
//
// This implementation uses optimized multi-round functions (Rounds4HW and Rounds6WithFinalHW)
// for maximum performance. Hardware acceleration is automatically used when available.
//
// Security: The 4+6 round configuration with feed-forward at round 4 provides security
// against known cryptanalytic attacks on AES-PRF constructions.
func (prf *AESPRF) PRF(block *Block) {
// Save the original input for feed-forward
var original Block
original = *block
// Initial AddRoundKey
AddRoundKey(block, prf.ks.GetRoundKey(0))
// Apply 4 full rounds using optimized multi-round function
var keys4 RoundKeys4
for i := 0; i < 4; i++ {
keys4[i] = *prf.ks.GetRoundKey(i + 1)
}
Rounds4HW(block, &keys4)
// Feed-forward: XOR with original input
XorBlock(block, &original, block)
// Apply 5 full rounds + 1 final round using optimized multi-round function
var keys6 RoundKeys6
for i := 0; i < 6; i++ {
keys6[i] = *prf.ks.GetRoundKey(i + 5)
}
Rounds6WithFinalHW(block, &keys6)
}