14
14
// You should have received a copy of the GNU Lesser General Public License
15
15
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16
16
17
+ //go:build ziren
18
+ // +build ziren
19
+
17
20
package crypto
18
21
19
22
import (
20
- "errors"
21
- "syscall"
22
- "unsafe"
23
-
23
+ "github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime"
24
24
"github.com/ethereum/go-ethereum/common"
25
25
originalcrypto "github.com/ethereum/go-ethereum/crypto"
26
26
)
27
27
28
- // Ziren zkVM system call numbers
29
- const (
30
- // SYS_KECCAK_SPONGE is the system call number for keccak sponge compression in Ziren zkVM
31
- // This performs the keccak-f[1600] permutation on a 1600-bit (200-byte) state
32
- SYS_KECCAK_SPONGE = 0x010109
33
- )
34
-
35
- // Keccak256 constants
36
- const (
37
- keccakRate = 136 // 1088 bits = 136 bytes for keccak256
38
- keccakCapacity = 64 // 512 bits = 64 bytes
39
- keccakStateSize = 200 // 1600 bits = 200 bytes
40
- )
41
-
42
- // zirenKeccakSponge calls the Ziren zkVM keccak sponge compression function
43
- // This performs the keccak-f[1600] permutation on the 200-byte state
44
- func zirenKeccakSponge (state * [keccakStateSize ]byte ) error {
45
- _ , _ , errno := syscall .Syscall (
46
- SYS_KECCAK_SPONGE ,
47
- uintptr (unsafe .Pointer (state )), // State pointer (input/output)
48
- 0 , 0 , // Unused parameters
49
- )
50
-
51
- if errno != 0 {
52
- return errors .New ("keccak sponge syscall failed" )
53
- }
54
-
55
- return nil
56
- }
57
-
58
- // zirenKeccak256 implements full keccak256 using the Ziren sponge syscall
59
- func zirenKeccak256 (data []byte ) []byte {
60
- // Initialize state to zeros
61
- var state [keccakStateSize ]byte
62
-
63
- // Pad input according to keccak256 specification
64
- // Padding: append 0x01, then zero or more 0x00 bytes, then 0x80
65
- padded := make ([]byte , len (data ))
66
- copy (padded , data )
67
- padded = append (padded , 0x01 ) // Domain separator for keccak256
68
-
69
- // Pad to multiple of rate (136 bytes for keccak256)
70
- for len (padded )% keccakRate != (keccakRate - 1 ) {
71
- padded = append (padded , 0x00 )
72
- }
73
- padded = append (padded , 0x80 ) // Final padding bit
74
-
75
- // Absorb phase: process input in chunks of rate size
76
- for i := 0 ; i < len (padded ); i += keccakRate {
77
- // XOR current chunk with state
78
- for j := 0 ; j < keccakRate && i + j < len (padded ); j ++ {
79
- state [j ] ^= padded [i + j ]
80
- }
81
-
82
- // Apply keccak-f[1600] permutation via syscall
83
- if err := zirenKeccakSponge (& state ); err != nil {
84
- // Fallback to standard implementation on error
85
- return originalcrypto .Keccak256 (data )
86
- }
87
- }
88
-
89
- // Squeeze phase: extract 32 bytes (256 bits) for keccak256
90
- result := make ([]byte , 32 )
91
- copy (result , state [:32 ])
92
-
93
- return result
94
- }
95
-
96
28
// Re-export everything from original crypto package except the parts we're overriding
97
29
var (
98
30
S256 = originalcrypto .S256
@@ -116,166 +48,43 @@ type (
116
48
KeccakState = originalcrypto.KeccakState
117
49
)
118
50
119
- // zirenKeccakState implements crypto.KeccakState using the Ziren sponge precompile
120
- type zirenKeccakState struct {
121
- state [keccakStateSize ]byte // 200-byte keccak state
122
- absorbed int // Number of bytes absorbed into current block
123
- buffer [keccakRate ]byte // Rate-sized buffer for current block
124
- finalized bool // Whether absorption is complete
125
- }
126
-
127
- func (k * zirenKeccakState ) Reset () {
128
- for i := range k .state {
129
- k .state [i ] = 0
130
- }
131
- for i := range k .buffer {
132
- k .buffer [i ] = 0
133
- }
134
- k .absorbed = 0
135
- k .finalized = false
136
- }
137
-
138
- func (k * zirenKeccakState ) Clone () KeccakState {
139
- clone := & zirenKeccakState {
140
- absorbed : k .absorbed ,
141
- finalized : k .finalized ,
142
- }
143
- copy (clone .state [:], k .state [:])
144
- copy (clone .buffer [:], k .buffer [:])
145
- return clone
146
- }
147
-
148
- func (k * zirenKeccakState ) Write (data []byte ) (int , error ) {
149
- if k .finalized {
150
- panic ("write to finalized keccak state" )
151
- }
152
-
153
- written := 0
154
- for len (data ) > 0 {
155
- // Fill current block
156
- canWrite := keccakRate - k .absorbed
157
- if canWrite > len (data ) {
158
- canWrite = len (data )
159
- }
160
-
161
- copy (k .buffer [k .absorbed :], data [:canWrite ])
162
- k .absorbed += canWrite
163
- data = data [canWrite :]
164
- written += canWrite
165
-
166
- // If block is full, absorb it
167
- if k .absorbed == keccakRate {
168
- k .absorbBlock ()
169
- }
170
- }
171
-
172
- return written , nil
173
- }
174
-
175
- // absorbBlock XORs the current buffer into state and applies the sponge permutation
176
- func (k * zirenKeccakState ) absorbBlock () {
177
- // XOR buffer into state
178
- for i := 0 ; i < keccakRate ; i ++ {
179
- k .state [i ] ^= k .buffer [i ]
180
- }
181
-
182
- // Apply keccak-f[1600] permutation via Ziren syscall
183
- if err := zirenKeccakSponge (& k .state ); err != nil {
184
- // On error, fallback to standard Go implementation
185
- // This shouldn't happen in production but provides safety
186
- fallbackState := originalcrypto .NewKeccakState ()
187
- fallbackState .Reset ()
188
- fallbackState .Write (k .buffer [:k .absorbed ])
189
- fallbackState .Read (k .state [:32 ])
190
- }
191
-
192
- // Reset buffer
193
- k .absorbed = 0
194
- for i := range k .buffer {
195
- k .buffer [i ] = 0
196
- }
197
- }
198
-
199
- func (k * zirenKeccakState ) Read (hash []byte ) (int , error ) {
200
- if len (hash ) < 32 {
201
- return 0 , errors .New ("hash slice too short" )
202
- }
203
-
204
- if ! k .finalized {
205
- k .finalize ()
206
- }
207
-
208
- copy (hash [:32 ], k .state [:32 ])
209
- return 32 , nil
210
- }
211
-
212
- // finalize completes the absorption phase with padding
213
- func (k * zirenKeccakState ) finalize () {
214
- // Add keccak256 padding: 0x01, then zeros, then 0x80
215
- k .buffer [k .absorbed ] = 0x01
216
- k .absorbed ++
217
-
218
- // Pad with zeros until we have room for final bit
219
- for k .absorbed < keccakRate - 1 {
220
- k .buffer [k .absorbed ] = 0x00
221
- k .absorbed ++
222
- }
223
-
224
- // Add final padding bit
225
- k .buffer [keccakRate - 1 ] = 0x80
226
- k .absorbed = keccakRate
227
-
228
- // Absorb final block
229
- k .absorbBlock ()
230
- k .finalized = true
231
- }
232
-
233
- func (k * zirenKeccakState ) Sum (data []byte ) []byte {
234
- hash := make ([]byte , 32 )
235
- k .Read (hash )
236
- return append (data , hash ... )
237
- }
238
-
239
- func (k * zirenKeccakState ) Size () int {
240
- return 32
241
- }
242
-
243
- func (k * zirenKeccakState ) BlockSize () int {
244
- return 136 // keccak256 block size
245
- }
246
-
247
- // Keccak256 calculates and returns the Keccak256 hash using the ziren platform precompile.
51
+ // Keccak256 calculates and returns the Keccak256 hash using the Ziren zkvm_runtime implementation.
248
52
func Keccak256 (data ... []byte ) []byte {
249
53
// For multiple data chunks, concatenate them
250
54
if len (data ) == 0 {
251
- return zirenKeccak256 (nil )
55
+ result := zkvm_runtime .Keccak256 (nil )
56
+ return result [:]
252
57
}
253
58
if len (data ) == 1 {
254
- return zirenKeccak256 (data [0 ])
59
+ result := zkvm_runtime .Keccak256 (data [0 ])
60
+ return result [:]
255
61
}
256
-
62
+
257
63
// Concatenate multiple data chunks
258
64
var totalLen int
259
65
for _ , d := range data {
260
66
totalLen += len (d )
261
67
}
262
-
68
+
263
69
combined := make ([]byte , 0 , totalLen )
264
70
for _ , d := range data {
265
71
combined = append (combined , d ... )
266
72
}
267
-
268
- return zirenKeccak256 (combined )
73
+
74
+ result := zkvm_runtime .Keccak256 (combined )
75
+ return result [:]
269
76
}
270
77
271
- // Keccak256Hash calculates and returns the Keccak256 hash as a Hash using the ziren platform precompile .
78
+ // Keccak256Hash calculates and returns the Keccak256 hash as a Hash using the Ziren zkvm_runtime implementation .
272
79
func Keccak256Hash (data ... []byte ) (h common.Hash ) {
273
80
hash := Keccak256 (data ... )
274
81
copy (h [:], hash )
275
82
return h
276
83
}
277
84
278
- // NewKeccakState returns a new keccak state hasher using the ziren platform precompile.
85
+ // NewKeccakState returns a new keccak state hasher.
86
+ // For now, we fallback to the original implementation for the stateful interface.
87
+ // TODO: Implement a stateful wrapper around zkvm_runtime.Keccak256 if needed.
279
88
func NewKeccakState () KeccakState {
280
- return & zirenKeccakState {}
281
- }
89
+ return originalcrypto . NewKeccakState ()
90
+ }
0 commit comments