Skip to content

Commit

Permalink
Add Blake2sadduint256bigend hint (#319)
Browse files Browse the repository at this point in the history
* Implement Blake2sAddUint256Bigend hint

* Add tests

* Fix missing err check

* Add more tests

* Change testing approach

* Remove unnecessary mod operations + clean up assertions in tests
  • Loading branch information
har777 committed Mar 29, 2024
1 parent d7281a1 commit 73a2a57
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 0 deletions.
1 change: 1 addition & 0 deletions pkg/hintrunner/zero/hintcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const (
// ------ Signature hints related code ------

// ------ Blake Hash hints related code ------
blake2sAddUint256BigendCode string = "B = 32\nMASK = 2 ** 32 - 1\nsegments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)])\nsegments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])"

// ------ Keccak hints related code ------

Expand Down
3 changes: 3 additions & 0 deletions pkg/hintrunner/zero/zerohint.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ func GetHintFromCode(program *zero.ZeroProgram, rawHint zero.Hint, hintPC uint64
return createUint256SqrtHinter(resolver)
case uint256MulDivModCode:
return createUint256MulDivModHinter(resolver)
// Blake hints
case blake2sAddUint256BigendCode:
return createBlake2sAddUint256BigendHinter(resolver)
// Other hints
case allocSegmentCode:
return createAllocSegmentHinter(resolver)
Expand Down
84 changes: 84 additions & 0 deletions pkg/hintrunner/zero/zerohint_blake.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package zero

import (
"github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter"
VM "github.com/NethermindEth/cairo-vm-go/pkg/vm"
mem "github.com/NethermindEth/cairo-vm-go/pkg/vm/memory"
"github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
"math"
"math/big"
)

func newBlake2sAddUint256BigendHint(low, high, data hinter.ResOperander) hinter.Hinter {
return &GenericZeroHinter{
Name: "Blake2sAddUint256Bigend",
Op: func(vm *VM.VirtualMachine, _ *hinter.HintRunnerContext) error {
//> B = 32
//> MASK = 2 ** 32 - 1
//> segments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)])
//> segments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])

low, err := hinter.ResolveAsFelt(vm, low)
if err != nil {
return err
}
high, err := hinter.ResolveAsFelt(vm, high)
if err != nil {
return err
}
dataPtr, err := hinter.ResolveAsAddress(vm, data)
if err != nil {
return err
}

var lowBig big.Int
var highBig big.Int
low.BigInt(&lowBig)
high.BigInt(&highBig)

const b uint64 = 32
mask := new(big.Int).SetUint64(math.MaxUint32)

for i := uint64(0); i < 4; i++ {
shift := uint(b * (3 - i))

highResultBig := new(big.Int).Set(&highBig)
highResultBig.Rsh(highResultBig, shift).And(highResultBig, mask)
highResultFelt := new(fp.Element).SetBigInt(highResultBig)
mvHigh := mem.MemoryValueFromFieldElement(highResultFelt)
err = vm.Memory.Write(dataPtr.SegmentIndex, dataPtr.Offset+i, &mvHigh)
if err != nil {
return err
}

lowResultBig := new(big.Int).Set(&lowBig)
lowResultBig.Rsh(lowResultBig, shift).And(lowResultBig, mask)
lowResultFelt := new(fp.Element).SetBigInt(lowResultBig)
mvLow := mem.MemoryValueFromFieldElement(lowResultFelt)
err = vm.Memory.Write(dataPtr.SegmentIndex, dataPtr.Offset+i+4, &mvLow)
if err != nil {
return err
}
}

return nil
},
}
}

func createBlake2sAddUint256BigendHinter(resolver hintReferenceResolver) (hinter.Hinter, error) {
low, err := resolver.GetResOperander("low")
if err != nil {
return nil, err
}
high, err := resolver.GetResOperander("high")
if err != nil {
return nil, err
}
data, err := resolver.GetResOperander("data")
if err != nil {
return nil, err
}

return newBlake2sAddUint256BigendHint(low, high, data), nil
}
222 changes: 222 additions & 0 deletions pkg/hintrunner/zero/zerohint_blake_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
package zero

import (
"testing"

"github.com/NethermindEth/cairo-vm-go/pkg/hintrunner/hinter"
"github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
)

func TestZeroHintBlake(t *testing.T) {
runHinterTests(t, map[string][]hintTestCase{
"Blake2sAddUint256Bigend": {
{
// 2**256 - 1
operanders: []*hintOperander{
{Name: "high", Kind: fpRelative, Value: feltString("10633823966279317261796329637309054975")},
{Name: "low", Kind: fpRelative, Value: feltString("340282366920938463463374607431768211424")},
{Name: "data", Kind: apRelative, Value: addr(7)},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newBlake2sAddUint256BigendHint(ctx.operanders["low"], ctx.operanders["high"], ctx.operanders["data"])
},
check: consecutiveVarAddrResolvedValueEquals(
"data",
[]*fp.Element{
feltString("134217727"),
feltString("4294966768"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967264"),
}),
},
{
// 2**256
operanders: []*hintOperander{
{Name: "high", Kind: fpRelative, Value: feltString("10633823966279317261796329637309054975")},
{Name: "low", Kind: fpRelative, Value: feltString("340282366920938463463374607431768211425")},
{Name: "data", Kind: apRelative, Value: addr(7)},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newBlake2sAddUint256BigendHint(ctx.operanders["low"], ctx.operanders["high"], ctx.operanders["data"])
},
check: consecutiveVarAddrResolvedValueEquals(
"data",
[]*fp.Element{
feltString("134217727"),
feltString("4294966768"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967265"),
}),
},
{
// 2**400
operanders: []*hintOperander{
{Name: "high", Kind: fpRelative, Value: feltString("10633629342298111006479807194589036544")},
{Name: "low", Kind: fpRelative, Value: feltString("21044980667851464052662337537")},
{Name: "data", Kind: apRelative, Value: addr(7)},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newBlake2sAddUint256BigendHint(ctx.operanders["low"], ctx.operanders["high"], ctx.operanders["data"])
},
check: consecutiveVarAddrResolvedValueEquals(
"data",
[]*fp.Element{
feltString("134215271"),
feltString("2147483664"),
feltString("4294967295"),
feltString("4292870144"),
feltString("0"),
feltString("1140850687"),
feltString("4294967151"),
feltString("2147483649"),
}),
},
{
// 689
operanders: []*hintOperander{
{Name: "high", Kind: fpRelative, Value: feltString("0")},
{Name: "low", Kind: fpRelative, Value: feltString("689")},
{Name: "data", Kind: apRelative, Value: addr(7)},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newBlake2sAddUint256BigendHint(ctx.operanders["low"], ctx.operanders["high"], ctx.operanders["data"])
},
check: consecutiveVarAddrResolvedValueEquals(
"data",
[]*fp.Element{
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("689"),
}),
},
{
// 2**128 - 1
operanders: []*hintOperander{
{Name: "high", Kind: fpRelative, Value: feltString("0")},
{Name: "low", Kind: fpRelative, Value: feltString("340282366920938463463374607431768211455")},
{Name: "data", Kind: apRelative, Value: addr(7)},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newBlake2sAddUint256BigendHint(ctx.operanders["low"], ctx.operanders["high"], ctx.operanders["data"])
},
check: consecutiveVarAddrResolvedValueEquals(
"data",
[]*fp.Element{
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967295"),
feltString("4294967295"),
}),
},
{
// 2**128
operanders: []*hintOperander{
{Name: "high", Kind: fpRelative, Value: feltString("1")},
{Name: "low", Kind: fpRelative, Value: feltString("0")},
{Name: "data", Kind: apRelative, Value: addr(7)},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newBlake2sAddUint256BigendHint(ctx.operanders["low"], ctx.operanders["high"], ctx.operanders["data"])
},
check: consecutiveVarAddrResolvedValueEquals(
"data",
[]*fp.Element{
feltString("0"),
feltString("0"),
feltString("0"),
feltString("1"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
}),
},
{
// 0 or modulus()
operanders: []*hintOperander{
{Name: "high", Kind: fpRelative, Value: feltString("0")},
{Name: "low", Kind: fpRelative, Value: feltString("0")},
{Name: "data", Kind: apRelative, Value: addr(7)},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newBlake2sAddUint256BigendHint(ctx.operanders["low"], ctx.operanders["high"], ctx.operanders["data"])
},
check: consecutiveVarAddrResolvedValueEquals(
"data",
[]*fp.Element{
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
}),
},
{
// modulus() - 1
operanders: []*hintOperander{
{Name: "high", Kind: fpRelative, Value: feltString("10633823966279327296825105735305134080")},
{Name: "low", Kind: fpRelative, Value: feltString("0")},
{Name: "data", Kind: apRelative, Value: addr(7)},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newBlake2sAddUint256BigendHint(ctx.operanders["low"], ctx.operanders["high"], ctx.operanders["data"])
},
check: consecutiveVarAddrResolvedValueEquals(
"data",
[]*fp.Element{
feltString("134217728"),
feltString("17"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
}),
},
{
// modulus() + 1
operanders: []*hintOperander{
{Name: "high", Kind: fpRelative, Value: feltString("0")},
{Name: "low", Kind: fpRelative, Value: feltString("1")},
{Name: "data", Kind: apRelative, Value: addr(7)},
},
makeHinter: func(ctx *hintTestContext) hinter.Hinter {
return newBlake2sAddUint256BigendHint(ctx.operanders["low"], ctx.operanders["high"], ctx.operanders["data"])
},
check: consecutiveVarAddrResolvedValueEquals(
"data",
[]*fp.Element{
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("0"),
feltString("1"),
}),
},
},
})
}
20 changes: 20 additions & 0 deletions pkg/hintrunner/zero/zerohint_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,26 @@ func varValueEquals(varName string, expected *fp.Element) func(t *testing.T, ctx
}
}

func consecutiveVarAddrResolvedValueEquals(varName string, expectedValues []*fp.Element) func(t *testing.T, ctx *hintTestContext) {
return func(t *testing.T, ctx *hintTestContext) {
o := ctx.operanders[varName]

addr, err := o.GetAddress(ctx.vm)
require.NoError(t, err)

actualAddress, err := ctx.vm.Memory.ReadFromAddressAsAddress(&addr)
require.NoError(t, err)

for index, expectedValue := range expectedValues {
expectedValueAddr := memory.MemoryAddress{SegmentIndex: actualAddress.SegmentIndex, Offset: actualAddress.Offset + uint64(index)}
actualFelt, err := ctx.vm.Memory.ReadFromAddressAsElement(&expectedValueAddr)
require.NoError(t, err)

require.Equal(t, &actualFelt, expectedValue, "%s[%v] value mismatch:\nhave: %v\nwant: %v", varName, index, &actualFelt, expectedValue)
}
}
}

func allVarValueEquals(expectedValues map[string]*fp.Element) func(t *testing.T, ctx *hintTestContext) {
return func(t *testing.T, ctx *hintTestContext) {
for varName, expected := range expectedValues {
Expand Down

0 comments on commit 73a2a57

Please sign in to comment.