Skip to content
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

Bugfix/eip 196 edge case #185

Merged
merged 1 commit into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ input,result,gas,notes
16eea4cc6a5c21b361c4d144f81f0c5774181b19b6341ebc3317b6d9c78b493407abc49d40a88a2336ea698f6bcc5b767f290fa5255f1ea9c449237dfa75259210264114425d52ebb998a32b103fe50d3c44b156f53dd16fec92c805c51b3bc117986b497207e3198ca7beb705537ba0d6c82cb8e6e1c507e74dece3fbb17fc2,2ef81763011baa4945a15da4c312cd2c280017994fcbea76048907c58acaf8f01a66e2bd9a4c4e1ca39a7fa9ba43f615c3720ae73c0d2aa6b2cb14e5a24f233d,150,
1ca0717a8dfb9c3940a731d7c52f1699f64fe05e76189a91dc622e8fafd99de62313a1df5b32b17c21e53e2d0a1ff3eeac6ab4359a9f86e51b1c236f414d87ea0e9729271df80f9967d618c33d9e8389bd4afb88e8b1e26e20b98868406da8ce1aca0647ae2e8573e39970f442aa3900175beeef2984af814fa51cf4ab59e07c,278782b7f77402d99c21f0bb831e899431703967252026abb6a6cfefd6d368600bd99290fca19622267066ee211842111904f2ced987023a34048236be757231,150,
1ca0717a8dfb9c3940a731d7c52f1699f64fe05e76189a91dc622e8fafd99de62313a1df5b32b17c21e53e2d0a1ff3eeac6ab4359a9f86e51b1c236f414d87ea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,1ca0717a8dfb9c3940a731d7c52f1699f64fe05e76189a91dc622e8fafd99de62313a1df5b32b17c21e53e2d0a1ff3eeac6ab4359a9f86e51b1c236f414d87ea,150,
1234,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,invalid input parameters, Point 0 is not on curve
1234,,150,invalid input parameters, Point 0 is not on curve
0174fc233104c2ad4f56a8396b8c1b7d9c6ad10bffc70761c5e8f5280862f137029733a9f20a4cdbb7ae9c5dd1adf6ccc7fe3439d7dc71093af0656ae0ca0f290964773f12e2292f332306374f957d10,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,invalid input parameters, Point 1 is not on curve
67376aad340c93eb0fc9bc8e040dc691bd00e426c6456b4d13079e7f1dbb3da847eb0fc271cd23da50c6ebc261928abb1af9bfcea998791e18af1817b06221e1fe708d2f4224275523fcd37460a310ce4b56f1694dfe36280410f0fb6efc5f47b85662e5b08d881242a72acbc2c8e2fa71ac593be977ad3e090c8158aace0247,,150,invalid input parameters, Failed to parse Fp element
,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,
ff000000000000000000000000000000000000000000000000000000000000ff,,150,invalid input parameters, Failed to parse Fp element
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ input,result,gas,notes
1c2cb2b4504b19c7e073679432e625f2706b7c4728cd9bd3ce36579f4de2f3902c8605f723ac2f73baa15eac674f62ab06c79809aa4a4be3391c4d41d5a6e62ca0a73a5b559cd0384ca11d444e34f40e04f2080483db9e54ae09e44ec19c26a1,1147da8fc5774b5ef94fda682437b04f9b6aea72987d1269496769baf7e67dc729fe144eab44c6da4c851123165cd6506ce3e10b7691b8bf11b757e2ae058fcb,6000,
0d6ad8e12b4f61e3e2a2252ce11428941f2a84b7f0a821cb8cc7699303bd4fec2247870562618fd8d6169072d9b33614d2acf800b3ba0ff68ef8d5fd4d6c250d3e70b3bed17894f958579644c83fa9d485121d580e2b061c697e68f950297768,0be6d75e2fe2887835d396dae11321ca7c53083abd6a0b270ee1c087593517aa2ffd1bad577de7cf2b19b82bfff0c66e2afbfb79a72cbe834290437f3caf2f21,6000,
d2acf800b3ba0ff68ef8d5fd4d6c250d3e70b3bed17894f958579644c83fa9d485121d580e2b061c697e68f9502977680d6ad8e12b4f61e3e2a2252ce11428941f2a84b7f0a821cb8cc7699303bd4fec2247870562618fd8d6169072d9b33614,,6000,invalid input parameters, Failed to parse Fp element
1c2cb2b4504b19c7e073679432e625f2706b7c4728cd9bd3ce36579f4de2f3902c8605f723ac2f73baa15eac674f62ab,,6000,invalid input parameters
,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,6000,
1A87B0584CE92F4593D161480614F2989035225609F08058CCFA3D0F940FEBE31A2F3C951F6DADCC7EE9007DFF81504B0FCD6D7CF59996EFDC33D92BF7F9F8F60100000000000000000000000000000000,0x220cb1540fa85ba04d863dca86de9359a43ac9fc084aebb9f2a936d989abbb602ccdc6c020dd2cf78332132b3f1d1122391b515035623cd6f53d4aea24ea2466,6000,
1A87B0584CE92F4593D161480614F2989035225609F08058CCFA3D0F940FEBE31A2F3C951F6DADCC7EE9007DFF81504B0FCD6D7CF59996EFDC33D92BF7F9F8F60000000000000000000000000000000100000000000000000000000000000000,1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b,6000,
116 changes: 87 additions & 29 deletions gnark/gnark-jni/gnark-eip-196.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import (
"github.com/consensys/gnark-crypto/ecc/bn254/fp"
)

var ErrMalformedPoint = errors.New("invalid input parameters, invalid point encoding")
var ErrPointNotInField = errors.New("invalid input parameters, point not in field")
var ErrPointOnCurveCheckFailed = errors.New("invalid point: point is not on curve")

const (
EIP196PreallocateForResult = 128
EIP196PreallocateForError = 256
Expand All @@ -26,9 +30,14 @@ const (
EIP196PreallocateForG2 = EIP196PreallocateForG1 * 2 // G2 points are encoded as 2 concatenated G1 points
)

var ErrSubgroupCheckFailed = errors.New("invalid point: subgroup check failed")
var ErrPointOnCurveCheckFailed = errors.New("invalid point: point is not on curve")
var ErrMalformedOutputBytes = errors.New("malformed output buffer parameter")

// bn254Modulus is the value 21888242871839275222246405745257275088696311157297823662689037894645226208583
var bn254Modulus = new(big.Int).SetBytes([]byte{
0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29,
0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81, 0x58, 0x5d,
0x97, 0x81, 0x6a, 0x91, 0x68, 0x71, 0xca, 0x8d,
0x3c, 0x20, 0x8c, 0x16, 0xd8, 0x7c, 0xfd, 0x47,
})

// Predefine a zero slice of length 16
var zeroSlice = make([]byte, 16)
Expand All @@ -38,29 +47,37 @@ func eip196altbn128G1Add(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInp
inputLen := int(cInputLen)
errorLen := int(cErrorLen)


if (inputLen > 2*EIP196PreallocateForG1) {
// trunc if input too long
inputLen = 2*EIP196PreallocateForG1
}

if inputLen < EIP196PreallocateForG1 {
// if we do not have complete input, return 0
return 0
}

// Convert error C pointers to Go slices
errorBuf := castErrorBuffer(javaErrorBuf, errorLen)

// check we have input size sufficient for a G1Affine
if inputLen < EIP196PreallocateForG1 {

// if not, check the X point and return an error if it is in the field, edge case
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// if not, check the X point and return an error if it is in the field, edge case
// if not, check the X point and return an error if it is not in the field, edge case

if inputLen >= EIP196PreallocateForFp {
input := (*[EIP196PreallocateForFp]byte)(unsafe.Pointer(javaInputBuf))[:EIP196PreallocateForFp:EIP196PreallocateForFp]
if !checkInField(input[:EIP196PreallocateForFp]) {
copy(errorBuf, ErrPointNotInField.Error())
return 1
}
}
// otherwise if we do not have complete input, return 0
return 0
}

// Convert input C pointers to Go slices
input := (*[2*EIP196PreallocateForG1]byte)(unsafe.Pointer(javaInputBuf))[:inputLen:inputLen]

// generate p0 g1 affine
var p0 bn254.G1Affine
err := p0.Unmarshal(input[:64])
p0, err := safeUnmarshal(input[:64])

if err != nil {
copy(errorBuf, err.Error())
copy(errorBuf, "invalid input parameters, " + err.Error())
return 1
}

Expand All @@ -69,20 +86,24 @@ func eip196altbn128G1Add(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInp
if isAllZero(input[64:inputLen]) {
ret := p0.Marshal()
g1AffineEncode(ret, javaOutputBuf)
return 0;
} else {
// else return an incomplete input error
copy(errorBuf, ErrMalformedPoint.Error())
return 1
}
return 0;
}

// generate p1 g1 affine
var p1 bn254.G1Affine
err = p1.Unmarshal(input[64:])
p1, err := safeUnmarshal(input[64:])

if err != nil {
copy(errorBuf, err.Error())
copy(errorBuf, "invalid input parameters, " + err.Error())
return 1
}

// Use the Add method to combine points
result := p0.Add(&p0, &p1)
result := p0.Add(p0, p1)

// marshal the resulting point and encode directly to the output buffer
ret := result.Marshal()
Expand All @@ -100,7 +121,17 @@ func eip196altbn128G1Mul(javaInputBuf, javaOutputBuf, javaErrorBuf *C.char, cInp
errorBuf := castErrorBuffer(javaErrorBuf, errorLen)

if inputLen < EIP196PreallocateForG1 {
// if we do not have complete input, return 0

// check the X point and return an error if it is in the field, edge case
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// check the X point and return an error if it is in the field, edge case
// check the X point and return an error if it is not in the field, edge case

if inputLen >= EIP196PreallocateForFp {
input := (*[EIP196PreallocateForFp]byte)(unsafe.Pointer(javaInputBuf))[:EIP196PreallocateForFp:EIP196PreallocateForFp]
if !checkInField(input[:EIP196PreallocateForFp]) {
copy(errorBuf, ErrPointNotInField.Error())
return 1
}
}

// otherwise if we do not have complete input, return 0
return 0
}

Expand Down Expand Up @@ -226,6 +257,43 @@ func g1AffineEncode(g1Point []byte, output *C.char) (error) {
return nil
}

func safeUnmarshal(input []byte) (*bn254.G1Affine, error) {
var g1 bn254.G1Affine
err := g1.X.SetBytesCanonical(input[:32])
if (err == nil) {
err := g1.Y.SetBytesCanonical(input[32:64])
if (err == nil) {
return &g1, nil
}
}
if (!g1.IsOnCurve()) {
return nil, ErrPointOnCurveCheckFailed
}

return nil, err
}

// checkInField checks that an element is in the field, not-in-field will normally
// be caught during unmarshal, but here in case of no-op calls of a single parameter
func checkInField(data []byte) bool {

// Convert the byte slice to a big.Int
elem := new(big.Int).SetBytes(data)

// Compare the value to the bn254Modulus
return bn254Modulus.Cmp(elem) == 1
}

// isAllZero checks if all elements in the byte slice are zero
func isAllZero(data []byte) bool {
for _, b := range data {
if b != 0 {
return false
}
}
return true
}

func castBufferToSlice(buf unsafe.Pointer, length int) []byte {
var slice []byte
// Obtain the slice header
Expand Down Expand Up @@ -253,9 +321,6 @@ func castErrorBuffer(javaOutputBuf *C.char, length int) []byte {
return (*[EIP196PreallocateForError]byte)(unsafe.Pointer(javaOutputBuf))[:bufSize:bufSize]
}

func main() {
}

// generate g1Add test data suitable for unit test input csv
func generateTestDataForAdd() {
// generate a point from a field element
Expand Down Expand Up @@ -311,12 +376,5 @@ func Uint256ToStringBigEndian(number *big.Int) string {
return hex.EncodeToString(bytes)
}

// isAllZero checks if all elements in the byte slice are zero
func isAllZero(data []byte) bool {
for _, b := range data {
if b != 0 {
return false
}
}
return true
func main() {
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public void shouldCalculate() {
} else {
final Bytes actualComputation = Bytes.wrap(output, 0, outputLength.getValue());
assertThat(actualComputation).isEqualTo(expectedComputation);
assertThat(notes).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ input,result,gas,notes
16eea4cc6a5c21b361c4d144f81f0c5774181b19b6341ebc3317b6d9c78b493407abc49d40a88a2336ea698f6bcc5b767f290fa5255f1ea9c449237dfa75259210264114425d52ebb998a32b103fe50d3c44b156f53dd16fec92c805c51b3bc117986b497207e3198ca7beb705537ba0d6c82cb8e6e1c507e74dece3fbb17fc2,2ef81763011baa4945a15da4c312cd2c280017994fcbea76048907c58acaf8f01a66e2bd9a4c4e1ca39a7fa9ba43f615c3720ae73c0d2aa6b2cb14e5a24f233d,150,
1ca0717a8dfb9c3940a731d7c52f1699f64fe05e76189a91dc622e8fafd99de62313a1df5b32b17c21e53e2d0a1ff3eeac6ab4359a9f86e51b1c236f414d87ea0e9729271df80f9967d618c33d9e8389bd4afb88e8b1e26e20b98868406da8ce1aca0647ae2e8573e39970f442aa3900175beeef2984af814fa51cf4ab59e07c,278782b7f77402d99c21f0bb831e899431703967252026abb6a6cfefd6d368600bd99290fca19622267066ee211842111904f2ced987023a34048236be757231,150,
1ca0717a8dfb9c3940a731d7c52f1699f64fe05e76189a91dc622e8fafd99de62313a1df5b32b17c21e53e2d0a1ff3eeac6ab4359a9f86e51b1c236f414d87ea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,1ca0717a8dfb9c3940a731d7c52f1699f64fe05e76189a91dc622e8fafd99de62313a1df5b32b17c21e53e2d0a1ff3eeac6ab4359a9f86e51b1c236f414d87ea,150,
1234,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,invalid input parameters, invalid input length for G1 addition
0174fc233104c2ad4f56a8396b8c1b7d9c6ad10bffc70761c5e8f5280862f137029733a9f20a4cdbb7ae9c5dd1adf6ccc7fe3439d7dc71093af0656ae0ca0f290964773f12e2292f332306374f957d10,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,invalid input parameters, invalid input length for G1 addition
67376aad340c93eb0fc9bc8e040dc691bd00e426c6456b4d13079e7f1dbb3da847eb0fc271cd23da50c6ebc261928abb1af9bfcea998791e18af1817b06221e1fe708d2f4224275523fcd37460a310ce4b56f1694dfe36280410f0fb6efc5f47b85662e5b08d881242a72acbc2c8e2fa71ac593be977ad3e090c8158aace0247,,150,invalid infinity point encoding
1234,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,
0174fc233104c2ad4f56a8396b8c1b7d9c6ad10bffc70761c5e8f5280862f137029733a9f20a4cdbb7ae9c5dd1adf6ccc7fe3439d7dc71093af0656ae0ca0f290964773f12e2292f332306374f957d10,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,invalid input parameters, invalid point encoding
67376aad340c93eb0fc9bc8e040dc691bd00e426c6456b4d13079e7f1dbb3da847eb0fc271cd23da50c6ebc261928abb1af9bfcea998791e18af1817b06221e1fe708d2f4224275523fcd37460a310ce4b56f1694dfe36280410f0fb6efc5f47b85662e5b08d881242a72acbc2c8e2fa71ac593be977ad3e090c8158aace0247,,150,invalid input parameters, invalid fp.Element encoding
,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,150,
ff000000000000000000000000000000000000000000000000000000000000ff,,150,invalid input parameters, point not in field
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ input,result,gas,notes
1c2cb2b4504b19c7e073679432e625f2706b7c4728cd9bd3ce36579f4de2f3902c8605f723ac2f73baa15eac674f62ab06c79809aa4a4be3391c4d41d5a6e62ca0a73a5b559cd0384ca11d444e34f40e04f2080483db9e54ae09e44ec19c26a1,1147da8fc5774b5ef94fda682437b04f9b6aea72987d1269496769baf7e67dc729fe144eab44c6da4c851123165cd6506ce3e10b7691b8bf11b757e2ae058fcb,6000,
0d6ad8e12b4f61e3e2a2252ce11428941f2a84b7f0a821cb8cc7699303bd4fec2247870562618fd8d6169072d9b33614d2acf800b3ba0ff68ef8d5fd4d6c250d3e70b3bed17894f958579644c83fa9d485121d580e2b061c697e68f950297768,0be6d75e2fe2887835d396dae11321ca7c53083abd6a0b270ee1c087593517aa2ffd1bad577de7cf2b19b82bfff0c66e2afbfb79a72cbe834290437f3caf2f21,6000,
d2acf800b3ba0ff68ef8d5fd4d6c250d3e70b3bed17894f958579644c83fa9d485121d580e2b061c697e68f9502977680d6ad8e12b4f61e3e2a2252ce11428941f2a84b7f0a821cb8cc7699303bd4fec2247870562618fd8d6169072d9b33614,,6000,invalid compressed coordinate
1c2cb2b4504b19c7e073679432e625f2706b7c4728cd9bd3ce36579f4de2f3902c8605f723ac2f73baa15eac674f62ab,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,6000,invalid input parameters,
1c2cb2b4504b19c7e073679432e625f2706b7c4728cd9bd3ce36579f4de2f3902c8605f723ac2f73baa15eac674f62ab,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,6000,
,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,6000,
1A87B0584CE92F4593D161480614F2989035225609F08058CCFA3D0F940FEBE31A2F3C951F6DADCC7EE9007DFF81504B0FCD6D7CF59996EFDC33D92BF7F9F8F60100000000000000000000000000000000,0x220cb1540fa85ba04d863dca86de9359a43ac9fc084aebb9f2a936d989abbb602ccdc6c020dd2cf78332132b3f1d1122391b515035623cd6f53d4aea24ea2466,6000,
1A87B0584CE92F4593D161480614F2989035225609F08058CCFA3D0F940FEBE31A2F3C951F6DADCC7EE9007DFF81504B0FCD6D7CF59996EFDC33D92BF7F9F8F60000000000000000000000000000000100000000000000000000000000000000,1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b,6000,
Loading