cairo-vm-go icon indicating copy to clipboard operation
cairo-vm-go copied to clipboard

feat: Replace secp_utils usage of `big.Int` with uint256 library.

Open TAdev0 opened this issue 1 year ago • 36 comments

Resolves #353

TAdev0 avatar Apr 17 '24 13:04 TAdev0

@rodrigo-pino i have a few questions :

should i also modify SecPPacked and SecPSplit functions?

Also, GetSecPBig for example now returns a uint256.Int, i guess i should also modify the code where this utils is used (i.e., zerohint_ec.go and zerohint_signature(s).go ) ?

TAdev0 avatar Apr 17 '24 13:04 TAdev0

Hey @TAdev0! Yes please add both functions since their values are never bigger than the 256 bits space. Regarding the code that uses them, it must be updated as well since we need the CI to pass in order to merge.

In case the consecuences of using uint64 library are very hard to integrate we can do smth good enough now and follow it up with another PR focused on that

rodrigo-pino avatar Apr 17 '24 13:04 rodrigo-pino

@rodrigo-pino ready for a first review. Not sure everything is correct with my syntax.

TAdev0 avatar Apr 17 '24 14:04 TAdev0

There are some errors. Especially compilations one. Could you please fix them.

Also you can test most of the CI by doing make unit. This will compile & run all unit tests.

rodrigo-pino avatar Apr 17 '24 14:04 rodrigo-pino

@rodrigo-pino yeah thank you! i'm installing Go right now, will do that.

TAdev0 avatar Apr 17 '24 14:04 TAdev0

@rodrigo-pino I have residual mismatch issues, for example:

   zerohint_utils_test.go:163: value scope value mismatch:
            have: 25711014748331347274616151948719391133326249308066029554892800
            want: 25711014748331348032841661176477624755444844903972403171819520

I double checked that i correctly defined constants in GetSecP , getBase and GetSecp256R1_P.

I suspect that the issue comes from SecPPacked as it is the common denominator for all failing tests. But i'm struggling debugging efficiently, i checked if it could come from DivMod which behaves differently with BigInt and uint256, but it seems ok.

TAdev0 avatar Apr 17 '24 16:04 TAdev0

I suspect that the issue comes from SecPPacked as it is the common denominator for all failing tests. But i'm struggling debugging efficiently, i checked if it could come from DivMod which behaves differently with BigInt and uint256, but it seems ok.

I see that's weird, maybe something to do with references? My tip for debugging would be testing the failing functions one by one with some prints scattered around. You'll eventually find the wrong piece of code

rodrigo-pino avatar Apr 18 '24 09:04 rodrigo-pino

@rodrigo-pino comments addressed. I still need to figure out this issue.

TAdev0 avatar Apr 18 '24 09:04 TAdev0

Ok left some other small ones, regarding the issue, I'll try to look it later. Can you debug it manually with prints?

rodrigo-pino avatar Apr 18 '24 10:04 rodrigo-pino

@rodrigo-pino ok so basically, i fail for all EcNegate tests (and others, but i think the root cause is the same). These tests call newEcNegateHint , which will use GetSecPUint256 and SecPPacked among other stuff i didnt change.

GetSecPUint256 returns a const which should be fine. I tried printing different variables and indeed, the result value of newEcNegateHint, which is yBig , is always a little bit different, with generally 8 identical bytes and the rest different.

yBig is the NEG + MOD result of SecPPacked , and SecPPacked seems ok as well, using getBaseUint256 .

I even tried keeping BigInt for SecPPacked computation, without any modification, and i still have these errors.

TAdev0 avatar Apr 18 '24 10:04 TAdev0

I did a super quick check. In SecPPacked before returning the packedBig variable I tried converting it to a uint256 and then back to a big.Int and tests failed.

Before:

return *packedBig, nil

After:

packedUint256 := new(uint256.Int)
packedUint256.SetFromBig(packedBig)

return *packedUint256.ToBig(), nil

The failing tests seem to be using quite large values though. Could it be the test values are just unrealistic? Though I would say the results should match the python vm regardless.

har777 avatar Apr 18 '24 11:04 har777

By looking at the python VM code you immediately realize that input values are always less than 256 bits, and output values are always smaller as well. This means that assuming the current implementation is correct, the one with big.Ints was flawed. It is possible the tests are actually not returning a correct value by using wrong inputs.

The python and the go vm should always return the same value, but if the python vm expect always it's input to be in the 256 bits range, whatever we throw at it bigger than it is not valid for comparison. We are loooking to match the python vm in the 256 bit range not on bigger stuff, assuming of course, that to the python VM you could feed bigger stuff, to which there is not test to show it.

rodrigo-pino avatar Apr 18 '24 11:04 rodrigo-pino

If there is a test that inputs a number bigger than 256 bits or returns as an output a number bigger than 256 bits, that test is not correct.

rodrigo-pino avatar Apr 18 '24 11:04 rodrigo-pino

If there is a test that inputs a number bigger than 256 bits or returns as an output a number bigger than 256 bits, that test is not correct.

The inputs are not larger than 256 bits in the tests. The outputs can be. The output can be a scope value and not a memory value.

har777 avatar Apr 18 '24 11:04 har777

In the case of secp packed the result should be a 256 bit number though.

har777 avatar Apr 18 '24 11:04 har777

If there is a test that inputs a number bigger than 256 bits or returns as an output a number bigger than 256 bits, that test is not correct.

The inputs are not larger than 256 bits in the tests. The outputs can be. The output can be a scope value and not a memory value.

If it works like this, then it is also problematic in terms of replacing scope any interface with the new struct, if the values are bigger then 256 bits, but that is not relevant in this scope.

MaksymMalicki avatar Apr 18 '24 11:04 MaksymMalicki

The weird thing is that my impl with uint256 is supposed to be the same. I guess there is some issue related to bigint to uint256 conversion for the output if all inputs are indeed < 256bits

Or I did something wrong

TAdev0 avatar Apr 18 '24 12:04 TAdev0

The inputs are not larger than 256 bits in the tests. The outputs can be. The output can be a scope value and not a memory value.

How can they be? The only way to get a higher than 256 bits is in packed right? Looking at the Cairo VM description it is stated that the number that needs to be formed needs to be in that range.

That Python doesn't have statically typed values doesn't mean we have to follow through if it doesn't make sense. I haven't studied this part long enough, but it feels to me that both pack and split are meant to use in tandem. So I don't see why the inputs forpack should be bigger than 256 bits

rodrigo-pino avatar Apr 18 '24 12:04 rodrigo-pino

... The output can be a scope value and not a memory value.

I am not convinced either that a scope value can be bigger than 256 bits. Obviously the python VM allows it (python allows many things by itself). The question is, is there any Cairo 0 code that could be written that could create a number bigger than 256 bits in the scope.

Also, remember that the Scope was defined by us as well, so using it as an argument of what it can have inside or not is not valid since we can always redefine it.

rodrigo-pino avatar Apr 18 '24 12:04 rodrigo-pino

The weird thing is that my impl with uint256 is supposed to be the same. I guess there is some issue related to bigint to uint256 conversion for the output if all inputs are indeed < 256bits ...

I think you've solved it correctly and we are finding some inconsistencies unrelated with them. After this PR the VM will be better

rodrigo-pino avatar Apr 18 '24 12:04 rodrigo-pino

The inputs are not larger than 256 bits in the tests. The outputs can be. The output can be a scope value and not a memory value.

How can they be? The only way to get a higher than 256 bits is in packed right? Looking at the Cairo VM description it is stated that the number that needs to be formed needs to be in that range.

That Python doesn't have statically typed values doesn't mean we have to follow through if it doesn't make sense. I haven't studied this part long enough, but it feels to me that both pack and split are meant to use in tandem. So I don't see why the inputs forpack should be bigger than 256 bits

  1. No input in the tests are larger than 256 bits.
  2. It's possible that the 3 values passed to pack is resulting in a value greater than 256 bits in the tests. I haven't checked this.
  3. I'm guessing the programmer must assert the input ranges of the arguments to pack in the cairo code. If they don't then the python vm and our vm will result in differing results written to the scope. I don't know if any programmer will have a valid reason for doing something like this.

har777 avatar Apr 18 '24 12:04 har777

If we remove test cases where the 3 values passed to pack can result in a value > 256 bits then everything should be fine. But I am a bit uncomfortable with how our vm will silently write the wrong result to the scope in case the inputs aren't validated properly. I'd rather throw an error than silently fail? Not sure if that makes sense.

har777 avatar Apr 18 '24 12:04 har777

@har777 indeed if i replace SecPPacked with the previous version using bigInt, tests for ec pass. I confirm that the value after exponentiation, mul , add and packing in SecPPacked will be greater than type(uint256).max . But i still have 2 tests failing in this configuration:

--- FAIL: TestZeroHintEc (0.00s)
    --- FAIL: TestZeroHintEc/NondetBigint3V1_3 (0.00s)
        zerohint_utils_test.go:195: expected an error containing "num != 0", got nil err
--- FAIL: TestVerifyZeroHint (0.00s)
    --- FAIL: TestVerifyZeroHint/VerifyZero_1 (0.00s)
        zerohint_utils_test.go:197: 
                Error Trace:    /Users/tristan/Desktop/Dev/cairo-vm-go/pkg/hintrunner/zero/zerohint_utils_test.go:197
                                                        /Users/tristan/Desktop/Dev/cairo-vm-go/pkg/hintrunner/zero/zerohint_test.go:255
                                                        /Users/tristan/Desktop/Dev/cairo-vm-go/pkg/hintrunner/zero/zerohint_test.go:267
                Error:          Error "verify_zero: Invalid input (1, 1, 1)" does not contain "verify_zero: Invalid input (1, 1, 1)."
                Test:           TestVerifyZeroHint/VerifyZero_1
                ```

TAdev0 avatar Apr 18 '24 12:04 TAdev0

The first failing seems to be related to this code:

	if num.Cmp(uint256.NewInt(0)) != 0 {
		return nil, fmt.Errorf("num != 0")
	}

error is not thrown while it should The 2nd error is related to this code:

			if rUint256.Cmp(uint256.NewInt(0)) != 0 {
				return fmt.Errorf("verify_zero: Invalid input (%v, %v, %v)", valValues[0], valValues[1], valValues[2])
			}

Their might be an issue related to the Cmp version for uint256?

TAdev0 avatar Apr 18 '24 12:04 TAdev0

I dont think so. I tried changing just that part:

num2 := new(uint256.Int)
num2.SetFromBig(num)
if num2.Cmp(uint256.NewInt(0)) != 0 {
  return nil, fmt.Errorf("num != 0")
}

And it passed.

har777 avatar Apr 18 '24 12:04 har777

I also tried for DivMod it passes as well

TAdev0 avatar Apr 18 '24 13:04 TAdev0

Lets just remove the test. I was trying to make the results always be consistent with the python vm. If we are using uint256 then might as well assume the value will always be a uint256 written to scope. The test which fails makes no sense in that context.

har777 avatar Apr 18 '24 13:04 har777

@har777 you want to remove all failing tests? what is the reason for the 2 others failing? I cannot find any reason for now.

TAdev0 avatar Apr 18 '24 13:04 TAdev0

@har777 you want to remove all failing tests? what is the reason for the 2 others failing? I cannot find any reason for now.

Just this one:

    --- FAIL: TestZeroHintEc/NondetBigint3V1_3 (0.00s)
        zerohint_utils_test.go:195: expected an error containing "num != 0", got nil err

har777 avatar Apr 18 '24 13:04 har777

mmh i dont understand. If i remove this test, i still have many tests failing.

TAdev0 avatar Apr 18 '24 13:04 TAdev0