1414// You should have received a copy of the GNU Lesser General Public License
1515// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
1616
17+ //go:build ziren
18+ // +build ziren
19+
1720package crypto
1821
1922import (
20- "errors"
21- "syscall"
22- "unsafe"
23-
23+ "github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime"
2424 "github.com/ethereum/go-ethereum/common"
2525 originalcrypto "github.com/ethereum/go-ethereum/crypto"
2626)
2727
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-
9628// Re-export everything from original crypto package except the parts we're overriding
9729var (
9830 S256 = originalcrypto .S256
@@ -116,166 +48,43 @@ type (
11648 KeccakState = originalcrypto.KeccakState
11749)
11850
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.
24852func Keccak256 (data ... []byte ) []byte {
24953 // For multiple data chunks, concatenate them
25054 if len (data ) == 0 {
251- return zirenKeccak256 (nil )
55+ result := zkvm_runtime .Keccak256 (nil )
56+ return result [:]
25257 }
25358 if len (data ) == 1 {
254- return zirenKeccak256 (data [0 ])
59+ result := zkvm_runtime .Keccak256 (data [0 ])
60+ return result [:]
25561 }
256-
62+
25763 // Concatenate multiple data chunks
25864 var totalLen int
25965 for _ , d := range data {
26066 totalLen += len (d )
26167 }
262-
68+
26369 combined := make ([]byte , 0 , totalLen )
26470 for _ , d := range data {
26571 combined = append (combined , d ... )
26672 }
267-
268- return zirenKeccak256 (combined )
73+
74+ result := zkvm_runtime .Keccak256 (combined )
75+ return result [:]
26976}
27077
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 .
27279func Keccak256Hash (data ... []byte ) (h common.Hash ) {
27380 hash := Keccak256 (data ... )
27481 copy (h [:], hash )
27582 return h
27683}
27784
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.
27988func NewKeccakState () KeccakState {
280- return & zirenKeccakState {}
281- }
89+ return originalcrypto . NewKeccakState ()
90+ }
0 commit comments