Skip to content

Commit

Permalink
Feature/Poseidon-hash (#74)
Browse files Browse the repository at this point in the history
* test

* added poseidon form

* fixed poseidon inputs

* removed visualizer

* added max bn128 value validation

* updated dependency

* removed useless computed

* changed app-button color

* added space

* applied fixes after review

* changed poseidon constants comment

* fixed attributes naming

* removed unused types
  • Loading branch information
lilbonekit authored Oct 8, 2024
1 parent 3f9ae1b commit a47ecdd
Show file tree
Hide file tree
Showing 17 changed files with 5,211 additions and 16 deletions.
2 changes: 1 addition & 1 deletion components/AppButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ const buttonType = computed<ButtonType>(
--app-button-text-focused: var(--app-button-none-text-focused);
--app-button-text-active: var(--app-button-none-text-active);
--app-button-disabled-text: var(--disable-primary-main);
--app-button-disabled-text: var(--primary-main);
}
&--primary {
Expand Down
1 change: 1 addition & 0 deletions composables/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './use-form-validation'
export * from './use-notifications'
export * from './use-viewport-sizes'
export * from './use-poseidon'
129 changes: 129 additions & 0 deletions composables/use-poseidon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Source: https://github.com/iden3/circomlibjs/blob/main/src/poseidon_wasm.js
// DO NOT MODIFY!

/* eslint-disable @typescript-eslint/ban-ts-comment */
// @ts-nocheck
import { getCurveFromName } from 'ffjavascript'

import poseidonConstants from '@/constants/poseidon_constants_opt'
import assert from 'assert'

export type BigNumberish = string | bigint | number | Uint8Array

export interface Poseidon {
(arr: BigNumberish[], state?: BigNumberish, nOut?: number): Uint8Array
F: unknown
}

function unsringifyConstants(Fr, o) {
if (typeof o == 'string' && /^[0-9]+$/.test(o)) {
return Fr.e(o)
} else if (typeof o == 'string' && /^0x[0-9a-fA-F]+$/.test(o)) {
return Fr.e(o)
} else if (Array.isArray(o)) {
return o.map(unsringifyConstants.bind(null, Fr))
} else if (typeof o == 'object') {
if (o === null) return null
const res = {}
const keys = Object.keys(o)
keys.forEach(k => {
res[k] = unsringifyConstants(Fr, o[k])
})
return res
} else {
return o
}
}

export async function usePoseidon(): Promise<Poseidon> {
const bn128 = await getCurveFromName('bn128', true)

const F = bn128.Fr

const opt = unsringifyConstants(F, poseidonConstants)

const N_ROUNDS_F = 8
const N_ROUNDS_P = [
56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68,
]

const pow5 = a => F.mul(a, F.square(F.square(a, a)))

function poseidon(
inputs: BigNumberish[],
initState: BigNumberish,
nOut: number,
): Poseidon {
assert(inputs.length > 0)
assert(inputs.length <= N_ROUNDS_P.length)

if (initState) {
initState = F.e(initState)
} else {
initState = F.zero
}
nOut = nOut || 1

const t = inputs.length + 1
const nRoundsF = N_ROUNDS_F
const nRoundsP = N_ROUNDS_P[t - 2]
const C = opt.C[t - 2]
const S = opt.S[t - 2]
const M = opt.M[t - 2]
const P = opt.P[t - 2]

let state = [initState, ...inputs.map(a => F.e(a))]

state = state.map((a, i) => F.add(a, C[i]))

for (let r = 0; r < nRoundsF / 2 - 1; r++) {
state = state.map(a => pow5(a))
state = state.map((a, i) => F.add(a, C[(r + 1) * t + i]))
state = state.map((_, i) =>
state.reduce((acc, a, j) => F.add(acc, F.mul(M[j][i], a)), F.zero),
)
}
state = state.map(a => pow5(a))
state = state.map((a, i) => F.add(a, C[(nRoundsF / 2 - 1 + 1) * t + i]))
state = state.map((_, i) =>
state.reduce((acc, a, j) => F.add(acc, F.mul(P[j][i], a)), F.zero),
)
for (let r = 0; r < nRoundsP; r++) {
state[0] = pow5(state[0])
state[0] = F.add(state[0], C[(nRoundsF / 2 + 1) * t + r])

const s0 = state.reduce((acc, a, j) => {
return F.add(acc, F.mul(S[(t * 2 - 1) * r + j], a))
}, F.zero)
for (let k = 1; k < t; k++) {
state[k] = F.add(
state[k],
F.mul(state[0], S[(t * 2 - 1) * r + t + k - 1]),
)
}
state[0] = s0
}
for (let r = 0; r < nRoundsF / 2 - 1; r++) {
state = state.map(a => pow5(a))
state = state.map((a, i) =>
F.add(a, C[(nRoundsF / 2 + 1) * t + nRoundsP + r * t + i]),
)
state = state.map((_, i) =>
state.reduce((acc, a, j) => F.add(acc, F.mul(M[j][i], a)), F.zero),
)
}
state = state.map(a => pow5(a))
state = state.map((_, i) =>
state.reduce((acc, a, j) => F.add(acc, F.mul(M[j][i], a)), F.zero),
)

if (nOut == 1) {
return state[0]
} else {
return state.slice(0, nOut)
}
}

poseidon.F = F
return poseidon
}
2 changes: 2 additions & 0 deletions constants/bn128.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const MAX_BN128_SAFE_VALUE =
21888242871839275222246405745257275088548364400416034343698204186575808495617n
2 changes: 2 additions & 0 deletions constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './numbers.constant'
export * from './bytes.constant'
export * from './poseidon_constants_opt'
export * from './bn128.constants'
3,880 changes: 3,880 additions & 0 deletions constants/poseidon_constants_opt.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions enums/route-names.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export enum ROUTE_NAMES {
hashFunctionKeccak256Id = 'hash-function-keccak256-id',
hashFunctionSha256Id = 'hash-function-sha256-id',
hashFunctionRipemd160Id = 'hash-function-ripemd160-id',
hashFunctionPoseidon6Id = 'hash-function-poseidon6-id',
addressUtils = 'address-utils',
addressUtilsCommonAddresses = 'address-utils-common-addresses',
addressUtilsCreate = 'address-utils-create',
Expand Down
2 changes: 1 addition & 1 deletion forms/AbiEncodeForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ const init = async (): Promise<void> => {
isInitializing.value = true
try {
const { id } = router.currentRoute.value.params
const id = router.currentRoute.value.params.id
if (id && typeof id === 'string') {
const { attributes } = await linkShortener.getDataByLink(id)
Expand Down
Loading

0 comments on commit a47ecdd

Please sign in to comment.