-
Notifications
You must be signed in to change notification settings - Fork 34
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
[WIP] Constantine bindings #184
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Nischal Sharma <nischal@web3labs.com>
👀 just a tracking comment |
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.
There shouldn't be a need for indirection and allocation, the function can be called and write directly in the relevant buffer, see C, Rust and Go code as referemce.
Also is optimizing for ARM desirable?
On non-x86 Constantine compiles through uint128 as it's the most portable and best perf across all compilers. Both GCC and Clang support an add with overflow
called __builtin__addcll
but the perf is abysmal on GCC: https://gcc.godbolt.org/z/jdecvffaP see overall issue mratsim/constantine#357
I do have a plan for optimizing for ARM targets (see mratsim/constantine#200 ) but so far no time to tackle it.
cc @Vindaar as well as he is currently maintaining the external languages dependencies.
var inputSeq: seq[byte] = cast[seq[byte]](inputs[0 ..< inputsLen]) | ||
let status = ethereum_evm_precompiles.eth_evm_bn254_g1add(result, inputSeq) | ||
copyMem(r, addr result[0], rLen) | ||
return status |
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.
There shouldn't be a need for this indirection and allocation.
If from Nim (ptr, length) pair can be zero-copied transformed to openarrays with https://nim-lang.org/docs/system.html#toOpenArray%2Cptr.UncheckedArray%5BT%5D%2Cint%2Cint
If from C, Go, Rust, you can directly call eth_evm_bn254_g1add
because it's compiled to (ptr, len):
/**
* Elliptic Curve addition on BN254_Snarks
* (also called alt_bn128 in Ethereum specs
* and bn256 in Ethereum tests)
*
* Name: ECADD
*
* Inputs:
* - A G1 point P with coordinates (Px, Py)
* - A G1 point Q with coordinates (Qx, Qy)
*
* Each coordinate is a 32-byte bigEndian integer
* They are serialized concatenated in a byte array [Px, Py, Qx, Qy]
* If the length is less than 128 bytes, input is virtually padded with zeros.
* If the length is greater than 128 bytes, input is truncated to 128 bytes.
*
* Output
* - Output buffer MUST be of length 64 bytes
* - A G1 point R = P+Q with coordinates (Rx, Ry)
* - Status code:
* cttEVM_Success
* cttEVM_InvalidOutputSize
* cttEVM_IntLargerThanModulus
* cttEVM_PointNotOnCurve
*
* Spec https://eips.ethereum.org/EIPS/eip-196
*/
ctt_evm_status ctt_eth_evm_bn254_g1add(
byte* r, ptrdiff_t r_len,
const byte* inputs, ptrdiff_t inputs_len
) __attribute__((warn_unused_result));
See how to call SHA256 from C (same interface):
https://github.com/mratsim/constantine/blob/8db2639/examples-c/ethereum_evm_precompiles.c#L47-L51
byte result[32] = {0};
const char txt[] = "Foo, Bar and Baz are all friends.";
evm_status = ctt_eth_evm_sha256(result, 32, (const byte*)txt, sizeof(txt));
Rust slices to Nim with zero-copy or alloc:
https://github.com/mratsim/constantine/blob/8db2639/constantine-rust/constantine-ethereum-evm-precompiles/src/lib.rs#L53-L69
pub fn evm_bn254_g1add(
result: &mut [u8],
inputs: &[u8]
) -> Result<bool, ctt_evm_status> {
unsafe {
let status = ctt_eth_evm_bn254_g1add(
result.as_mut_ptr() as *mut byte,
result.len() as isize,
inputs.as_ptr() as *const byte,
inputs.len() as isize,
);
match status {
ctt_evm_status::cttEVM_Success => Ok(true),
_ => Err(status)
}
}
}
Go slices to Nim with zero-copy or alloc:
https://github.com/mratsim/constantine/blob/8db2639/constantine-go/constantine.go#L705-L718
func EvmBn254G1Mul(result []byte, inputs []byte) (bool, error) {
status := C.ctt_eth_evm_bn254_g1mul((*C.byte)(getAddr(result)),
(C.ptrdiff_t)(len(result)),
(*C.byte)(getAddr(inputs)),
(C.ptrdiff_t)(len(inputs)),
)
if status != C.cttEVM_Success {
err := errors.New(
C.GoString(C.ctt_evm_status_to_string(status)),
)
return false, err
}
return true, nil
}
One thing is that in an excess zeal moment I set the type to ptrdiff_t
but I'll change it to size_t
.
In general Constantine was written to minimize allocations and for precompiles it's only needed for MSMs and KZG point precompiles.
No description provided.