diff --git a/src/bindings b/src/bindings index 290d7b8fbc..89e2d3c295 160000 --- a/src/bindings +++ b/src/bindings @@ -1 +1 @@ -Subproject commit 290d7b8fbcdc7ecba2f8981811ee958800bc4ad5 +Subproject commit 89e2d3c295bb35dfe7bea6a318686c05c8023897 diff --git a/src/lib/hash.ts b/src/lib/hash.ts index cef036df3d..d4ba94caa1 100644 --- a/src/lib/hash.ts +++ b/src/lib/hash.ts @@ -1,5 +1,10 @@ -import { HashInput, ProvableExtended, Struct } from './circuit_value.js'; -import { Poseidon as Poseidon_, Field } from '../snarky.js'; +import { + HashInput, + provable, + ProvableExtended, + Struct, +} from './circuit_value.js'; +import { Poseidon as Poseidon_, Field, Bool, Circuit } from '../snarky.js'; import { inCheckedComputation } from './proof_system.js'; import { createHashHelpers } from './hash-generic.js'; @@ -43,6 +48,28 @@ const Poseidon = { return Poseidon_.hash(input, isChecked); }, + hashToGroup(input: Field[]) { + let isChecked = !input.every((x) => x.isConstant()); + // y = sqrt(y^2) + let { x, y } = Poseidon_.hashToGroup(input, isChecked); + + let x0 = Circuit.witness(Field, () => { + // the even root of y^2 will become x0, so the APIs are uniform + let isEven = y.toBigInt() % 2n === 0n; + + // we just change the order so the even root is x0 + // y.mul(-1); is the second root of sqrt(y^2) + return isEven ? y : y.mul(-1); + }); + + let x1 = x0.mul(-1); + + // we check that either x0 or x1 match the original root y + y.equals(x0).or(y.equals(x1)).assertTrue(); + + return { x, y: { x0, x1 } }; + }, + update(state: [Field, Field, Field], input: Field[]) { let isChecked = !( state.every((x) => x.isConstant()) && input.every((x) => x.isConstant()) diff --git a/src/snarky.d.ts b/src/snarky.d.ts index b9fcd7c58f..a23c38ae7f 100644 --- a/src/snarky.d.ts +++ b/src/snarky.d.ts @@ -1101,6 +1101,13 @@ declare const Poseidon: { input: Field[], isChecked: boolean ): [Field, Field, Field]; + hashToGroup( + input: Field[], + isChecked: boolean + ): { + x: Field; + y: Field; + }; prefixes: Record< | 'event' | 'events'