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

feat: binary operations for frontend.Variable #1265

Open
zliucd opened this issue Sep 2, 2024 · 3 comments
Open

feat: binary operations for frontend.Variable #1265

zliucd opened this issue Sep 2, 2024 · 3 comments
Labels
consolidate strengthen an existing feature new feature

Comments

@zliucd
Copy link

zliucd commented Sep 2, 2024

It would be very useful to provide more arithmetic operations for frontend.Variable, including:

  • left and right shift
  • rotate left and right shift

The arithmetic operations can be user-friendly APIs to use. Example code:

var X frontend.Variable
r0 := api.Lsh(X, 3)        // left shift
r1 := api.Rsh(X, 3)        // right shift
r2: = api.Lor(X, 3)       // left rotate shift
r3: = api.Ror(X, 3).     // right rotate shift

gnark/std/math/bits provide compatible types(e.g., U8), but direct APIs for Variable are more convenient.

I have implemented a demo:

/**
* Left shift input by `shift` bits  
* 
* Input:
*   - api:  gnark api
*   - X: input
*   - shift: number of bits to shift
* 
* Output: shifted result
*/
func Lsh(api frontend.API, X frontend.Variable, shift uint) frontend.Variable {

	var output frontend.Variable

	// bits: [LSB, MSB]
	bits := api.ToBinary(X)
	N := len(bits)

	// [zeroes, len: shift] + [bits, len: N - shift]
	bits_final := make([]frontend.Variable, len(bits))
	for i := 0; i < len(bits_final); i++ {
		bits_final[i] = 0
	}

	for i := shift; i < uint(N) - shift; i++ {
		bits_final[i] = bits[i - shift]
	}

	output = api.FromBinary(bits_final...)

	return output
} 
@ivokub
Copy link
Collaborator

ivokub commented Sep 3, 2024

Good idea. We have for now postponed implementing such methods as in general the arithmetic in circuits are done on field elements and doing bit operations is quite expensive (as we need to decompose the field elements to bits etc.). But I do see that this kind of functionality is needed anyway, so it would be good to have idiomatic way. But if we implement it, then I think it makes more sense to have them as gadgets (e.g. in std/ package) instead of extending frontend.API.

@ivokub ivokub changed the title More APIs of arithmetic operations for frontend.Variable feat: binary operations for frontend.Variable Sep 3, 2024
@ivokub ivokub added new feature consolidate strengthen an existing feature labels Sep 3, 2024
@zliucd
Copy link
Author

zliucd commented Sep 4, 2024

Thanks for the feedback especially shedding light on "bit operations is quite expensive". Another thought is the granuality of bitwise operations, which may potentially generate unexpected result.

Example:
a is a fixed 8-bit value , left shift by 4 bits should result in ( 0xc5 << 4 ) & 0xff = 0x50. Following code shows the unexpected result, as Variable has no semantics of bit level granularity.

var a, b frontend.Variable
a = 0xc5
b = Lsh(a, 4)     //   b = 0xc5 << 4 = 0x0c50 (16bit integer)

We can again use another gadget to perform AND to get correct result, e.g., result := and(b, 0xff). It would be nice to provide an option bits in binary gadgets for convenient use:

  • 0: no limit (original shifted result)
  • 8: lower 8 bits
  • 16: lower 16 bits
    ...

@ivokub
Copy link
Collaborator

ivokub commented Sep 5, 2024

See the https://pkg.go.dev/github.com/consensys/[email protected]/std/math/uints package which wraps the frontend.Variable type to allow byte operations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
consolidate strengthen an existing feature new feature
Projects
None yet
Development

No branches or pull requests

2 participants