-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
go-bindings: pass large arrays by ref instead of value #393
Changes from 4 commits
63bc236
4065f9d
445461e
4b7e233
c7d6ae9
8ed9355
c0abbd6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,10 +6,10 @@ package ckzg4844 | |
import "C" | ||
|
||
import ( | ||
"bytes" | ||
"encoding/hex" | ||
"errors" | ||
"fmt" | ||
"strings" | ||
"unsafe" | ||
|
||
// So its functions are available during compilation. | ||
|
@@ -38,12 +38,6 @@ var ( | |
ErrBadArgs = errors.New("bad arguments") | ||
ErrError = errors.New("unexpected error") | ||
ErrMalloc = errors.New("malloc failed") | ||
errorMap = map[C.C_KZG_RET]error{ | ||
C.C_KZG_OK: nil, | ||
C.C_KZG_BADARGS: ErrBadArgs, | ||
C.C_KZG_ERROR: ErrError, | ||
C.C_KZG_MALLOC: ErrMalloc, | ||
} | ||
) | ||
|
||
/////////////////////////////////////////////////////////////////////////////// | ||
|
@@ -54,62 +48,71 @@ var ( | |
// by the C library, into a proper Go error. If there is no error, this | ||
// will return nil. | ||
func makeErrorFromRet(ret C.C_KZG_RET) error { | ||
err, ok := errorMap[ret] | ||
if !ok { | ||
panic(fmt.Sprintf("unexpected return value: %v", ret)) | ||
switch ret { | ||
case C.C_KZG_BADARGS: | ||
return ErrBadArgs | ||
case C.C_KZG_ERROR: | ||
return ErrError | ||
case C.C_KZG_MALLOC: | ||
return ErrMalloc | ||
case C.C_KZG_OK: | ||
return nil | ||
} | ||
return err | ||
return fmt.Errorf("unexpected return value from c-library %v", ret) | ||
} | ||
|
||
/////////////////////////////////////////////////////////////////////////////// | ||
// Unmarshal Functions | ||
/////////////////////////////////////////////////////////////////////////////// | ||
|
||
func (b *Bytes32) UnmarshalText(input []byte) error { | ||
inputStr := string(input) | ||
if strings.HasPrefix(inputStr, "0x") { | ||
inputStr = strings.TrimPrefix(inputStr, "0x") | ||
if bytes.HasPrefix(input, []byte("0x")) { | ||
input = input[2:] | ||
} | ||
bytes, err := hex.DecodeString(inputStr) | ||
if len(input) != 2*len(b) { | ||
return ErrBadArgs | ||
} | ||
l, err := hex.Decode(b[:], input) | ||
if err != nil { | ||
return err | ||
} | ||
if len(bytes) != len(b) { | ||
if l != len(b) { | ||
return ErrBadArgs | ||
} | ||
copy(b[:], bytes) | ||
return nil | ||
} | ||
|
||
func (b *Bytes48) UnmarshalText(input []byte) error { | ||
inputStr := string(input) | ||
if strings.HasPrefix(inputStr, "0x") { | ||
inputStr = strings.TrimPrefix(inputStr, "0x") | ||
if bytes.HasPrefix(input, []byte("0x")) { | ||
input = input[2:] | ||
} | ||
bytes, err := hex.DecodeString(inputStr) | ||
if len(input) != 2*len(b) { | ||
return ErrBadArgs | ||
} | ||
l, err := hex.Decode(b[:], input) | ||
if err != nil { | ||
return err | ||
} | ||
if len(bytes) != len(b) { | ||
if l != len(b) { | ||
return ErrBadArgs | ||
} | ||
copy(b[:], bytes) | ||
return nil | ||
} | ||
|
||
func (b *Blob) UnmarshalText(input []byte) error { | ||
inputStr := string(input) | ||
if strings.HasPrefix(inputStr, "0x") { | ||
inputStr = strings.TrimPrefix(inputStr, "0x") | ||
if bytes.HasPrefix(input, []byte("0x")) { | ||
input = input[2:] | ||
} | ||
if len(input) != 2*len(b) { | ||
return ErrBadArgs | ||
} | ||
bytes, err := hex.DecodeString(inputStr) | ||
l, err := hex.Decode(b[:], input) | ||
if err != nil { | ||
return err | ||
} | ||
if len(bytes) != len(b) { | ||
if l != len(b) { | ||
return ErrBadArgs | ||
} | ||
copy(b[:], bytes) | ||
return nil | ||
} | ||
|
||
|
@@ -137,6 +140,7 @@ func LoadTrustedSetup(g1Bytes, g2Bytes []byte) error { | |
if len(g2Bytes)%C.BYTES_PER_G2 != 0 { | ||
panic(fmt.Sprintf("len(g2Bytes) is not a multiple of %v", C.BYTES_PER_G2)) | ||
} | ||
|
||
numG1Elements := len(g1Bytes) / C.BYTES_PER_G1 | ||
numG2Elements := len(g2Bytes) / C.BYTES_PER_G2 | ||
ret := C.load_trusted_setup( | ||
|
@@ -145,8 +149,10 @@ func LoadTrustedSetup(g1Bytes, g2Bytes []byte) error { | |
(C.size_t)(numG1Elements), | ||
*(**C.uint8_t)(unsafe.Pointer(&g2Bytes)), | ||
(C.size_t)(numG2Elements)) | ||
|
||
if ret == C.C_KZG_OK { | ||
loaded = true | ||
return nil | ||
} | ||
return makeErrorFromRet(ret) | ||
} | ||
|
@@ -174,6 +180,7 @@ func LoadTrustedSetupFile(trustedSetupFile string) error { | |
C.fclose(fp) | ||
if ret == C.C_KZG_OK { | ||
loaded = true | ||
return nil | ||
} | ||
return makeErrorFromRet(ret) | ||
} | ||
|
@@ -200,16 +207,24 @@ BlobToKZGCommitment is the binding for: | |
const Blob *blob, | ||
const KZGSettings *s); | ||
*/ | ||
func BlobToKZGCommitment(blob Blob) (KZGCommitment, error) { | ||
func BlobToKZGCommitment(blob *Blob) (*KZGCommitment, error) { | ||
if !loaded { | ||
panic("trusted setup isn't loaded") | ||
} | ||
commitment := KZGCommitment{} | ||
if blob == nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why so defensive? If caller sends in nil, he should not be surprised if a nil deref happens, imo There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rather be safe than sorry. It's a very simple check, might as well. |
||
return nil, ErrBadArgs | ||
} | ||
|
||
commitment := new(KZGCommitment) | ||
ret := C.blob_to_kzg_commitment( | ||
(*C.KZGCommitment)(unsafe.Pointer(&commitment)), | ||
(*C.Blob)(unsafe.Pointer(&blob)), | ||
(*C.KZGCommitment)(unsafe.Pointer(commitment)), | ||
(*C.Blob)(unsafe.Pointer(blob)), | ||
&settings) | ||
return commitment, makeErrorFromRet(ret) | ||
|
||
if ret != C.C_KZG_OK { | ||
return nil, makeErrorFromRet(ret) | ||
} | ||
return commitment, nil | ||
} | ||
|
||
/* | ||
|
@@ -222,19 +237,26 @@ ComputeKZGProof is the binding for: | |
const Bytes32 *z_bytes, | ||
const KZGSettings *s); | ||
*/ | ||
func ComputeKZGProof(blob Blob, zBytes Bytes32) (KZGProof, Bytes32, error) { | ||
func ComputeKZGProof(blob *Blob, zBytes *Bytes32) (*KZGProof, *Bytes32, error) { | ||
if !loaded { | ||
panic("trusted setup isn't loaded") | ||
} | ||
proof := KZGProof{} | ||
y := Bytes32{} | ||
if blob == nil || zBytes == nil { | ||
return nil, nil, ErrBadArgs | ||
} | ||
|
||
proof, y := new(KZGProof), new(Bytes32) | ||
ret := C.compute_kzg_proof( | ||
(*C.KZGProof)(unsafe.Pointer(&proof)), | ||
(*C.Bytes32)(unsafe.Pointer(&y)), | ||
(*C.Blob)(unsafe.Pointer(&blob)), | ||
(*C.Bytes32)(unsafe.Pointer(&zBytes)), | ||
(*C.KZGProof)(unsafe.Pointer(proof)), | ||
(*C.Bytes32)(unsafe.Pointer(y)), | ||
(*C.Blob)(unsafe.Pointer(blob)), | ||
(*C.Bytes32)(unsafe.Pointer(zBytes)), | ||
&settings) | ||
return proof, y, makeErrorFromRet(ret) | ||
|
||
if ret != C.C_KZG_OK { | ||
return nil, nil, makeErrorFromRet(ret) | ||
} | ||
return proof, y, nil | ||
} | ||
|
||
/* | ||
|
@@ -246,17 +268,25 @@ ComputeBlobKZGProof is the binding for: | |
const Bytes48 *commitment_bytes, | ||
const KZGSettings *s); | ||
*/ | ||
func ComputeBlobKZGProof(blob Blob, commitmentBytes Bytes48) (KZGProof, error) { | ||
func ComputeBlobKZGProof(blob *Blob, commitmentBytes *Bytes48) (*KZGProof, error) { | ||
if !loaded { | ||
panic("trusted setup isn't loaded") | ||
} | ||
proof := KZGProof{} | ||
if blob == nil || commitmentBytes == nil { | ||
return nil, ErrBadArgs | ||
} | ||
|
||
proof := new(KZGProof) | ||
ret := C.compute_blob_kzg_proof( | ||
(*C.KZGProof)(unsafe.Pointer(&proof)), | ||
(*C.Blob)(unsafe.Pointer(&blob)), | ||
(*C.Bytes48)(unsafe.Pointer(&commitmentBytes)), | ||
(*C.KZGProof)(unsafe.Pointer(proof)), | ||
(*C.Blob)(unsafe.Pointer(blob)), | ||
(*C.Bytes48)(unsafe.Pointer(commitmentBytes)), | ||
&settings) | ||
return proof, makeErrorFromRet(ret) | ||
|
||
if ret != C.C_KZG_OK { | ||
return nil, makeErrorFromRet(ret) | ||
} | ||
return proof, nil | ||
} | ||
|
||
/* | ||
|
@@ -270,19 +300,27 @@ VerifyKZGProof is the binding for: | |
const Bytes48 *proof_bytes, | ||
const KZGSettings *s); | ||
*/ | ||
func VerifyKZGProof(commitmentBytes Bytes48, zBytes, yBytes Bytes32, proofBytes Bytes48) (bool, error) { | ||
func VerifyKZGProof(commitmentBytes *Bytes48, zBytes, yBytes *Bytes32, proofBytes *Bytes48) (bool, error) { | ||
if !loaded { | ||
panic("trusted setup isn't loaded") | ||
} | ||
if commitmentBytes == nil || zBytes == nil || yBytes == nil || proofBytes == nil { | ||
return false, ErrBadArgs | ||
} | ||
|
||
var result C.bool | ||
ret := C.verify_kzg_proof( | ||
&result, | ||
(*C.Bytes48)(unsafe.Pointer(&commitmentBytes)), | ||
(*C.Bytes32)(unsafe.Pointer(&zBytes)), | ||
(*C.Bytes32)(unsafe.Pointer(&yBytes)), | ||
(*C.Bytes48)(unsafe.Pointer(&proofBytes)), | ||
(*C.Bytes48)(unsafe.Pointer(commitmentBytes)), | ||
(*C.Bytes32)(unsafe.Pointer(zBytes)), | ||
(*C.Bytes32)(unsafe.Pointer(yBytes)), | ||
(*C.Bytes48)(unsafe.Pointer(proofBytes)), | ||
&settings) | ||
return bool(result), makeErrorFromRet(ret) | ||
|
||
if ret != C.C_KZG_OK { | ||
return false, makeErrorFromRet(ret) | ||
} | ||
return bool(result), nil | ||
} | ||
|
||
/* | ||
|
@@ -295,18 +333,26 @@ VerifyBlobKZGProof is the binding for: | |
const Bytes48 *proof_bytes, | ||
const KZGSettings *s); | ||
*/ | ||
func VerifyBlobKZGProof(blob Blob, commitmentBytes, proofBytes Bytes48) (bool, error) { | ||
func VerifyBlobKZGProof(blob *Blob, commitmentBytes, proofBytes *Bytes48) (bool, error) { | ||
if !loaded { | ||
panic("trusted setup isn't loaded") | ||
} | ||
if blob == nil || commitmentBytes == nil || proofBytes == nil { | ||
return false, ErrBadArgs | ||
} | ||
|
||
var result C.bool | ||
ret := C.verify_blob_kzg_proof( | ||
&result, | ||
(*C.Blob)(unsafe.Pointer(&blob)), | ||
(*C.Bytes48)(unsafe.Pointer(&commitmentBytes)), | ||
(*C.Bytes48)(unsafe.Pointer(&proofBytes)), | ||
(*C.Blob)(unsafe.Pointer(blob)), | ||
(*C.Bytes48)(unsafe.Pointer(commitmentBytes)), | ||
(*C.Bytes48)(unsafe.Pointer(proofBytes)), | ||
&settings) | ||
return bool(result), makeErrorFromRet(ret) | ||
|
||
if ret != C.C_KZG_OK { | ||
return false, makeErrorFromRet(ret) | ||
} | ||
return bool(result), nil | ||
} | ||
|
||
/* | ||
|
@@ -335,5 +381,9 @@ func VerifyBlobKZGProofBatch(blobs []Blob, commitmentsBytes, proofsBytes []Bytes | |
*(**C.Bytes48)(unsafe.Pointer(&proofsBytes)), | ||
(C.size_t)(len(blobs)), | ||
&settings) | ||
return bool(result), makeErrorFromRet(ret) | ||
|
||
if ret != C.C_KZG_OK { | ||
return false, makeErrorFromRet(ret) | ||
} | ||
return bool(result), nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the
panic
here. I think libraries should generally avoidpanic
, especially in cases where they already have a channel to signal error - in this case just returning an error. The the caller can decide if it's panic-worthy or if it can clean up some files or whatever before exiting