mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 22:26:42 +00:00
move c code to a separate c file
This commit is contained in:
parent
f8cd00314e
commit
ee5e4361ea
3 changed files with 140 additions and 158 deletions
|
|
@ -1,168 +1,80 @@
|
||||||
package gmp
|
package gmp
|
||||||
|
|
||||||
// #cgo LDFLAGS: -lgmp
|
// #cgo LDFLAGS: -lgmp
|
||||||
// #include <gmp.h>
|
// #include "modexp.h"
|
||||||
// #include <stdlib.h>
|
|
||||||
// #include <string.h>
|
|
||||||
// #include <stdint.h>
|
|
||||||
//
|
|
||||||
// static int modexp_bytes(
|
|
||||||
// const uint8_t* base, size_t base_len,
|
|
||||||
// const uint8_t* exp, size_t exp_len,
|
|
||||||
// const uint8_t* mod, size_t mod_len,
|
|
||||||
// uint8_t* result, size_t* result_len)
|
|
||||||
// {
|
|
||||||
// mpz_t base_mpz, exp_mpz, mod_mpz, result_mpz;
|
|
||||||
//
|
|
||||||
// // Check for NULL pointers
|
|
||||||
// if (!base || !exp || !mod || !result || !result_len) {
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Initialize GMP integers
|
|
||||||
// mpz_inits(base_mpz, exp_mpz, mod_mpz, result_mpz, NULL);
|
|
||||||
//
|
|
||||||
// // Import big-endian byte arrays into GMP integers
|
|
||||||
// // Handle empty arrays specially - GMP treats NULL with size 0 as 0
|
|
||||||
// if (base_len > 0) {
|
|
||||||
// mpz_import(base_mpz, base_len, 1, 1, 0, 0, base);
|
|
||||||
// }
|
|
||||||
// if (exp_len > 0) {
|
|
||||||
// mpz_import(exp_mpz, exp_len, 1, 1, 0, 0, exp);
|
|
||||||
// }
|
|
||||||
// if (mod_len > 0) {
|
|
||||||
// mpz_import(mod_mpz, mod_len, 1, 1, 0, 0, mod);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Perform modular exponentiation
|
|
||||||
// mpz_powm(result_mpz, base_mpz, exp_mpz, mod_mpz);
|
|
||||||
//
|
|
||||||
// // Get exact size needed for result
|
|
||||||
// size_t needed = 0;
|
|
||||||
// mpz_export(NULL, &needed, 1, 1, 0, 0, result_mpz);
|
|
||||||
//
|
|
||||||
// // Check if result buffer is large enough
|
|
||||||
// if (*result_len < needed) {
|
|
||||||
// mpz_clears(base_mpz, exp_mpz, mod_mpz, result_mpz, NULL);
|
|
||||||
// return -2;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Export result to big-endian byte array
|
|
||||||
// mpz_export(result, &needed, 1, 1, 0, 0, result_mpz);
|
|
||||||
// *result_len = needed;
|
|
||||||
//
|
|
||||||
// // Clean up
|
|
||||||
// mpz_clears(base_mpz, exp_mpz, mod_mpz, result_mpz, NULL);
|
|
||||||
//
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ModExp performs modular exponentiation using GMP
|
||||||
// ModExp performs modular exponentiation using the C implementation directly
|
|
||||||
// This is a lower-level function that bypasses the Go wrapper types
|
|
||||||
//
|
|
||||||
// This is thread safe.
|
// This is thread safe.
|
||||||
func ModExp(base, exp, mod []byte) ([]byte, error) {
|
func ModExp(base, exp, mod []byte) ([]byte, error) {
|
||||||
// Handle empty modulus - return empty result (EVM behavior)
|
// Handle empty modulus - return empty result (EVM behavior)
|
||||||
if len(mod) == 0 {
|
if len(mod) == 0 {
|
||||||
return []byte{}, nil
|
return []byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case: zero modulus
|
// Special case: zero modulus
|
||||||
// TODO: Check to see if theres a cleaner way to do this
|
allZero := true
|
||||||
allZero := true
|
for _, b := range mod {
|
||||||
for _, b := range mod {
|
if b != 0 {
|
||||||
if b != 0 {
|
allZero = false
|
||||||
allZero = false
|
break
|
||||||
break
|
}
|
||||||
}
|
}
|
||||||
}
|
if allZero {
|
||||||
if allZero {
|
return []byte{}, nil
|
||||||
return []byte{}, nil
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// // Special case: base == 1
|
// Allocate result buffer (size of modulus is the max possible result)
|
||||||
// // Check if base is 1 (only one byte with value 1, or leading zeros followed by 1)
|
result := make([]byte, len(mod))
|
||||||
// baseIsOne := false
|
resultLen := C.size_t(len(result))
|
||||||
// if len(base) == 0 {
|
|
||||||
// baseIsOne = false
|
|
||||||
// } else if len(base) == 1 && base[0] == 1 {
|
|
||||||
// baseIsOne = true
|
|
||||||
// } else {
|
|
||||||
// // Check for leading zeros followed by 1
|
|
||||||
// allZeroExceptLast := true
|
|
||||||
// for i := 0; i < len(base)-1; i++ {
|
|
||||||
// if base[i] != 0 {
|
|
||||||
// allZeroExceptLast = false
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if allZeroExceptLast && base[len(base)-1] == 1 {
|
|
||||||
// baseIsOne = true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if baseIsOne {
|
// Handle empty slices - pass a dummy non-nil pointer with length 0
|
||||||
// // base^exp mod mod = 1 mod mod = 1 (if mod > 1), 0 (if mod == 1)
|
// This avoids UB when the length is zero.
|
||||||
// // Just return base % mod which is 1 % mod
|
dummy := C.uint8_t(0)
|
||||||
// if len(mod) == 1 && mod[0] == 1 {
|
var basePtr, expPtr, modPtr *C.uint8_t = &dummy, &dummy, &dummy
|
||||||
// return []byte{}, nil // 1 % 1 = 0
|
|
||||||
// }
|
|
||||||
// return []byte{1}, nil // 1 % mod = 1 for mod > 1
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Allocate result buffer (size of modulus is the max possible result)
|
if len(base) > 0 {
|
||||||
result := make([]byte, len(mod))
|
basePtr = (*C.uint8_t)(unsafe.Pointer(&base[0]))
|
||||||
resultLen := C.size_t(len(result))
|
}
|
||||||
|
if len(exp) > 0 {
|
||||||
|
expPtr = (*C.uint8_t)(unsafe.Pointer(&exp[0]))
|
||||||
|
}
|
||||||
|
if len(mod) > 0 {
|
||||||
|
modPtr = (*C.uint8_t)(unsafe.Pointer(&mod[0]))
|
||||||
|
}
|
||||||
|
|
||||||
// Handle empty slices - pass a dummy non-nil pointer with length 0
|
// Call C function
|
||||||
// This avoids UB when the length is zero.
|
ret := C.modexp_bytes(
|
||||||
dummy := C.uint8_t(0)
|
basePtr, C.size_t(len(base)),
|
||||||
var basePtr, expPtr, modPtr *C.uint8_t = &dummy, &dummy, &dummy
|
expPtr, C.size_t(len(exp)),
|
||||||
|
modPtr, C.size_t(len(mod)),
|
||||||
|
(*C.uint8_t)(unsafe.Pointer(&result[0])), &resultLen,
|
||||||
|
)
|
||||||
|
|
||||||
if len(base) > 0 {
|
// Keep the slices alive until after the C call completes
|
||||||
basePtr = (*C.uint8_t)(unsafe.Pointer(&base[0]))
|
runtime.KeepAlive(base)
|
||||||
}
|
runtime.KeepAlive(exp)
|
||||||
if len(exp) > 0 {
|
runtime.KeepAlive(mod)
|
||||||
expPtr = (*C.uint8_t)(unsafe.Pointer(&exp[0]))
|
runtime.KeepAlive(result)
|
||||||
}
|
|
||||||
if len(mod) > 0 {
|
|
||||||
modPtr = (*C.uint8_t)(unsafe.Pointer(&mod[0]))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call C function
|
// Check for errors
|
||||||
ret := C.modexp_bytes(
|
switch ret {
|
||||||
basePtr, C.size_t(len(base)),
|
case 0:
|
||||||
expPtr, C.size_t(len(exp)),
|
// Success - trim result to actual size
|
||||||
modPtr, C.size_t(len(mod)),
|
if resultLen == 0 {
|
||||||
(*C.uint8_t)(unsafe.Pointer(&result[0])), &resultLen,
|
return []byte{}, nil
|
||||||
)
|
}
|
||||||
|
return result[:resultLen], nil
|
||||||
// Keep the slices alive until after the C call completes
|
case -1:
|
||||||
runtime.KeepAlive(base)
|
return nil, errors.New("invalid parameter")
|
||||||
runtime.KeepAlive(exp)
|
case -2:
|
||||||
runtime.KeepAlive(mod)
|
return nil, errors.New("result buffer too small")
|
||||||
runtime.KeepAlive(result)
|
default:
|
||||||
|
return nil, errors.New("unknown error")
|
||||||
// Check for errors
|
}
|
||||||
switch ret {
|
|
||||||
case 0:
|
|
||||||
// Success - trim result to actual size
|
|
||||||
if resultLen == 0 {
|
|
||||||
return []byte{}, nil
|
|
||||||
}
|
|
||||||
return result[:resultLen], nil
|
|
||||||
case -1:
|
|
||||||
return nil, errors.New("invalid parameter")
|
|
||||||
case -2:
|
|
||||||
return nil, errors.New("result buffer too small")
|
|
||||||
default:
|
|
||||||
return nil, errors.New("unknown error")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
55
crypto/modexp/gmp/modexp.c
Normal file
55
crypto/modexp/gmp/modexp.c
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include <gmp.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int modexp_bytes(
|
||||||
|
const uint8_t* base, size_t base_len,
|
||||||
|
const uint8_t* exp, size_t exp_len,
|
||||||
|
const uint8_t* mod, size_t mod_len,
|
||||||
|
uint8_t* result, size_t* result_len)
|
||||||
|
{
|
||||||
|
mpz_t base_mpz, exp_mpz, mod_mpz, result_mpz;
|
||||||
|
|
||||||
|
// Check for NULL pointers
|
||||||
|
if (!base || !exp || !mod || !result || !result_len) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize GMP integers
|
||||||
|
mpz_inits(base_mpz, exp_mpz, mod_mpz, result_mpz, NULL);
|
||||||
|
|
||||||
|
// Import big-endian byte arrays into GMP integers
|
||||||
|
// Handle empty arrays specially - GMP treats NULL with size 0 as 0
|
||||||
|
if (base_len > 0) {
|
||||||
|
mpz_import(base_mpz, base_len, 1, 1, 0, 0, base);
|
||||||
|
}
|
||||||
|
if (exp_len > 0) {
|
||||||
|
mpz_import(exp_mpz, exp_len, 1, 1, 0, 0, exp);
|
||||||
|
}
|
||||||
|
if (mod_len > 0) {
|
||||||
|
mpz_import(mod_mpz, mod_len, 1, 1, 0, 0, mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform modular exponentiation
|
||||||
|
mpz_powm(result_mpz, base_mpz, exp_mpz, mod_mpz);
|
||||||
|
|
||||||
|
// Get exact size needed for result
|
||||||
|
size_t needed = 0;
|
||||||
|
mpz_export(NULL, &needed, 1, 1, 0, 0, result_mpz);
|
||||||
|
|
||||||
|
// Check if result buffer is large enough
|
||||||
|
if (*result_len < needed) {
|
||||||
|
mpz_clears(base_mpz, exp_mpz, mod_mpz, result_mpz, NULL);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export result to big-endian byte array
|
||||||
|
mpz_export(result, &needed, 1, 1, 0, 0, result_mpz);
|
||||||
|
*result_len = needed;
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
mpz_clears(base_mpz, exp_mpz, mod_mpz, result_mpz, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
15
crypto/modexp/gmp/modexp.h
Normal file
15
crypto/modexp/gmp/modexp.h
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef MODEXP_H
|
||||||
|
#define MODEXP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// Perform modular exponentiation: base^exp mod mod
|
||||||
|
// Returns 0 on success, -1 on invalid input, -2 if result buffer too small
|
||||||
|
int modexp_bytes(
|
||||||
|
const uint8_t* base, size_t base_len,
|
||||||
|
const uint8_t* exp, size_t exp_len,
|
||||||
|
const uint8_t* mod, size_t mod_len,
|
||||||
|
uint8_t* result, size_t* result_len);
|
||||||
|
|
||||||
|
#endif // MODEXP_H
|
||||||
Loading…
Reference in a new issue