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

[BUG]: Poseidon Hash Example Rust bindings #651

Open
AustinLiu01 opened this issue Nov 9, 2024 · 12 comments
Open

[BUG]: Poseidon Hash Example Rust bindings #651

AustinLiu01 opened this issue Nov 9, 2024 · 12 comments
Labels
type:bug Something isn't working

Comments

@AustinLiu01
Copy link

Description

Your developer manual says that using Poseidon Hash's API is as follows:
It suggests that you should instantiate a poseidon_hasher as follows
let poseidon_hasher = Poseidon::new::<ScalarField>(arity as u32).unwrap();
But actually I got an error:

error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> src/main.rs:114:27
    |
114 |     let poseidon_hasher = Poseidon::new::<ScalarField>(arity as u32).unwrap();
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------- an argument of type'Option<&Field<1, ScalarCfg>> is missing
    |
note: associated function defined here
   --> (my_address)/wrappers/rust/icicle-core/src/poseidon/mod.rs:27:12
    |
27  |     pub fn new<F>(t: u32, domain_tag: Option<&F>) -> Result<Hasher, eIcicleError>
    |            ^^^
help: provide the argument
    |
114 |     let poseidon_hasher = Poseidon::new::<ScalarField>(arity as u32, /* Option<&Field<1, ScalarCfg>> */).unwrap();
    |                                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When I checked my local as well as the github repo on the this path:
icicle/wrappers/rust/icicle-core/src/poseidon/mod.rs
There is a problem reported by the compiler, I would like to request the official update for this API, thank you!

Reproduce

Just run the example rust bindings in your developer manual.

Expected Behavior

Work

Environment

Please complete the following information:

OS + Version: Centos 7

Cargo Version: 1.80

@AustinLiu01 AustinLiu01 added the type:bug Something isn't working label Nov 9, 2024
@omershlo
Copy link
Member

omershlo commented Nov 9, 2024

Thank you!
cc: @danny-shterman

@yshekel
Copy link
Collaborator

yshekel commented Nov 9, 2024

You are right. To fix it you need to specify domain tag (or None)

let poseidon_hasher = Poseidon::new::<ScalarField>(arity as u32, None).unwrap();

We will update the docs soon. Thanks for letting us know.

@AustinLiu01
Copy link
Author

You are right. To fix it you need to specify domain tag (or None)

let poseidon_hasher = Poseidon::new::<ScalarField>(arity as u32, None).unwrap();

We will update the docs soon. Thanks for letting us know.

I also met a new issue. When I use this example to run the icicle_bn254-based Merkle Tree (but I replace the hash function here using Poseidon hash), I found I can't set the arity=2,but can to 3, but your markdown file shows that arity=2 could work. Once I set arity=2, rust gives me a Segmentation fault.

@danny-shterman
Copy link
Contributor

You can either use arity=3 and the second parameter as None or arity=2 and the second parameter should be a pointer to scalar_t

@AustinLiu01
Copy link
Author

You can either use arity=3 and the second parameter as None or arity=2 and the second parameter should be a pointer to scalar_t

could you give a simple example? What does "pointer to scalar_t mean" ? I haven't been learning rust particularly long, so this will sound a bit foreign to me, thank you very much

@yshekel
Copy link
Collaborator

yshekel commented Nov 9, 2024

This markdown is old and relevant to v2. Please ignore it. We support arity to be 3 5 9 12 regardless of domain tag. But note that if you do use domain tag, then you need to supply one less input so input size should be 2 4 8 or 11 accordingly. But still arity should be 3 5 9 or 12 since this defines the hash.

@AustinLiu01
Copy link
Author

AustinLiu01 commented Nov 9, 2024

This markdown is old and relevant to v2. Please ignore it. We support arity to be 3 5 9 12 regardless of domain tag. But note that if you do use domain tag, then you need to supply one less input so input size should be 2 4 8 or 11 accordingly. But still arity should be 3 5 9 or 12 since this defines the hash.

You mean, Arity is 2:1,4:1,8:1,11:1?

@yshekel
Copy link
Collaborator

yshekel commented Nov 9, 2024

You can either use arity=3 and the second parameter as None or arity=2 and the second parameter should be a pointer to scalar_t

could you give a simple example? What does "pointer to scalar_t mean" ? I haven't been learning rust particularly long, so this will sound a bit foreign to me, thank you very much

Domain tag is a field element that is used by the Poseidon hasher to differentiate different applications of Poseidon. If you don't want to you pass None as the domain tag. Otherwise just use Some(domain_tag_field_element) .

Can you maybe describe what you want to achieve?

@yshekel
Copy link
Collaborator

yshekel commented Nov 9, 2024

This markdown is old and relevant to v2. Please ignore it. We support arity to be 3 5 9 12 regardless of domain tag. But note that if you do use domain tag, then you need to supply one less input so input size should be 2 4 8 or 11 accordingly. But still arity should be 3 5 9 or 12 since this defines the hash.

You mean, Arity is 2:1,4:1,8:1,11:1?

Right, the arity is either 3:1 5:1 etc when no domain tag is used or 2:1 4:1 etc otherwise. Still the first param should be 3 5 etc. - this is the t parameter and actually not arity. Next version will support more cases.

@AustinLiu01
Copy link
Author

You can either use arity=3 and the second parameter as None or arity=2 and the second parameter should be a pointer to scalar_t

could you give a simple example? What does "pointer to scalar_t mean" ? I haven't been learning rust particularly long, so this will sound a bit foreign to me, thank you very much

Domain tag is a field element that is used by the Poseidon hasher to differentiate different applications of Poseidon. If you don't want to you pass None as the domain tag. Otherwise just use Some(domain_tag_field_element) .

Can you maybe describe what you want to achieve?

I want to build a Merkle Tree using ICICLE's Poseidon Hash, based on the ScalarField under the BLS12-381 curve, and I want Airty to be 2: 1, which means that this is a binary Merkle Tree, so I may need to add domain_tag as you described, can I just use "Some(domain_tag_field_element)"? Or I still have to make some other changes, Thank you!

@yshekel
Copy link
Collaborator

yshekel commented Nov 9, 2024

You can either use arity=3 and the second parameter as None or arity=2 and the second parameter should be a pointer to scalar_t

could you give a simple example? What does "pointer to scalar_t mean" ? I haven't been learning rust particularly long, so this will sound a bit foreign to me, thank you very much

Domain tag is a field element that is used by the Poseidon hasher to differentiate different applications of Poseidon. If you don't want to you pass None as the domain tag. Otherwise just use Some(domain_tag_field_element) .
Can you maybe describe what you want to achieve?

I want to build a Merkle Tree using ICICLE's Poseidon Hash, based on the ScalarField under the BLS12-381 curve, and I want Airty to be 2: 1, which means that this is a binary Merkle Tree, so I may need to add domain_tag as you described, can I just use "Some(domain_tag_field_element)"? Or I still have to make some other changes, Thank you!

So yes you could use Poseidon3 and use a domain-tag so that you only need 2 inputs per node and effectively build a binary tree. You can then open a single element as leaf or two elements (or more but I think it would not make much sense in your case).
To do that you would use the following hasher:
let poseidon_hasher = Poseidon::new::<ScalarField>(3 /*=t*/, Some(ScalarField::zero()) /*=doman_tag*/).unwrap(); assuming ScalarField is the type of the scalar_field. Of course you could use different field element for domain tag. It's simply used as the first input so you hash [domain_tag, input0, input1].
you can see an example here regarding domain_tag

let poseidon_hasher_main = Poseidon::new::<F>(t as u32, domain_tag).unwrap();

About the segmentation fault, didn't you get an error when constructing the hasher object? specifically this one

ICICLE_LOG_ERROR << "cpu_poseidon_init_default_constants: T (width) must be one of [3, 5, 9, 12]";

Anyway we will make sure to fix the docs and generate a clear error soon.

@AustinLiu01
Copy link
Author

You can either use arity=3 and the second parameter as None or arity=2 and the second parameter should be a pointer to scalar_t

could you give a simple example? What does "pointer to scalar_t mean" ? I haven't been learning rust particularly long, so this will sound a bit foreign to me, thank you very much

Domain tag is a field element that is used by the Poseidon hasher to differentiate different applications of Poseidon. If you don't want to you pass None as the domain tag. Otherwise just use Some(domain_tag_field_element) .
Can you maybe describe what you want to achieve?

I want to build a Merkle Tree using ICICLE's Poseidon Hash, based on the ScalarField under the BLS12-381 curve, and I want Airty to be 2: 1, which means that this is a binary Merkle Tree, so I may need to add domain_tag as you described, can I just use "Some(domain_tag_field_element)"? Or I still have to make some other changes, Thank you!

So yes you could use Poseidon3 and use a domain-tag so that you only need 2 inputs per node and effectively build a binary tree. You can then open a single element as leaf or two elements (or more but I think it would not make much sense in your case). To do that you would use the following hasher: let poseidon_hasher = Poseidon::new::<ScalarField>(3 /*=t*/, Some(ScalarField::zero()) /*=doman_tag*/).unwrap(); assuming ScalarField is the type of the scalar_field. Of course you could use different field element for domain tag. It's simply used as the first input so you hash [domain_tag, input0, input1]. you can see an example here regarding domain_tag

let poseidon_hasher_main = Poseidon::new::<F>(t as u32, domain_tag).unwrap();

About the segmentation fault, didn't you get an error when constructing the hasher object? specifically this one

ICICLE_LOG_ERROR << "cpu_poseidon_init_default_constants: T (width) must be one of [3, 5, 9, 12]";

Anyway we will make sure to fix the docs and generate a clear error soon.

Thanks for your reply, I saw some related updates in the repo! In fact, there are no other errors, except the Segement Fault. I will update the repo and try Poseidon Hash again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants