Skip to content

Commit

Permalink
Refactor Poseidon
Browse files Browse the repository at this point in the history
  • Loading branch information
DelevoXDG committed Jan 2, 2024
1 parent 02cd830 commit 2b60183
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 58 deletions.
61 changes: 7 additions & 54 deletions Sources/CryptoToolkit/CryptoPoseidon.swift
Original file line number Diff line number Diff line change
@@ -1,59 +1,12 @@
import BigInt
import CFrameworkWrapper
import Foundation

public class CryptoPoseidon {
public class func poseidonHash(x: BigUInt, y: BigUInt) -> BigUInt {
unsplitBigUInt(
hades(
[
splitBigUInt(x),
splitBigUInt(y),
(2, 0, 0, 0),
]
)[0]
)
}

private static func hades(_ values: [(UInt64, UInt64, UInt64, UInt64)]) -> [(UInt64, UInt64, UInt64, UInt64)] {
permutation3(values)
}

private static func permutation3(_ state: [(UInt64, UInt64, UInt64, UInt64)]) -> [(UInt64, UInt64, UInt64, UInt64)] {
var mutableState = state
permutation_3(&mutableState)
return mutableState
}

private static func splitBigUInt(_ value: BigUInt) -> (UInt64, UInt64, UInt64, UInt64) {
var result: [UInt64] = [0, 0, 0, 0]

// if the input is zero, return the array of zeros
if value != BigUInt(0) {
// mask has all bits set to 1 except the least significant one
let mask = BigUInt(2).power(64) - 1

// loop through the 64-bit chunks of the BigUInt, shift them and store in the LongArray
for i in 0 ..< 4 {
result[i] = UInt64(value >> (i * 64) & mask)
}
}

return (result[0], result[1], result[2], result[3])
}

/// <#Description#>
/// - Parameter values: <#values description#>
/// - Returns: <#description#>
private static func unsplitBigUInt(_ values: (UInt64, UInt64, UInt64, UInt64)) -> BigUInt {
var arr: [UInt64] = [values.0, values.1, values.2, values.3]
let powersOfTwo = [BigUInt(2).power(0), BigUInt(2).power(64), BigUInt(2).power(128), BigUInt(2).power(192)]

// w * 2**0 + x * 2**64 + y * 2**128 + z * 2**192
var result = BigUInt(0)
for (b, p) in zip(arr, powersOfTwo) {
result += BigUInt(b) * p
}
return result
public enum CryptoPoseidon {
public static func hades(
_ values: [(UInt64, UInt64, UInt64, UInt64)]
) -> [(UInt64, UInt64, UInt64, UInt64)] {
var state = values
permutation_3(&state)
return state
}
}
50 changes: 46 additions & 4 deletions Sources/Starknet/Crypto/Poseidon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,52 @@ import BigInt
import CryptoToolkit
import Foundation

public enum Poseidon {
public static func poseidonHash(x: Felt, y: Felt) -> Felt {
let result = CryptoPoseidon.poseidonHash(x: x.value, y: y.value)
public class Poseidon {
/// Compute poseidon hash on input values.
///
/// - Returns: Poseidon hash of the two values as Felt.
public class func poseidonHash(x: Felt, y: Felt) -> Felt {
let state = [
splitBigUInt(x.value),
splitBigUInt(y.value),
(2, 0, 0, 0),
]
return Felt(clamping: combineToBigUInt(
CryptoPoseidon.hades(state)[0]
))
}

private static func splitBigUInt(_ value: BigUInt) -> (UInt64, UInt64, UInt64, UInt64) {
var result: [UInt64] = [0, 0, 0, 0]

// if the input is zero, return the array of zeros
if value != BigUInt(0) {
// mask has all bits set to 1 except the least significant one
let mask = BigUInt(2).power(64) - 1

// loop through the 64-bit chunks of the BigUInt, shift them and store in the result array
for i in 0 ..< 4 {
result[i] = UInt64(value >> (i * 64) & mask)
}
}

return (result[0], result[1], result[2], result[3])
}

private static func combineToBigUInt(_ values: (UInt64, UInt64, UInt64, UInt64)) -> BigUInt {
let arr: [UInt64] = [values.0, values.1, values.2, values.3]
let powersOfTwo = [
BigUInt(2).power(0),
BigUInt(2).power(64),
BigUInt(2).power(128),
BigUInt(2).power(192),
]

return Felt(result)!
// w * 2**0 + x * 2**64 + y * 2**128 + z * 2**192
var result = BigUInt(0)
for (b, p) in zip(arr, powersOfTwo) {
result += BigUInt(b) * p
}
return result
}
}

0 comments on commit 2b60183

Please sign in to comment.