github.com/consensys/gnark-crypto@v0.14.0/ecc/stark-curve/pedersen-hash/pedersen_hash.go (about) 1 package pedersenhash 2 3 import ( 4 "math/big" 5 6 starkcurve "github.com/consensys/gnark-crypto/ecc/stark-curve" 7 "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" 8 ) 9 10 const nibbleCount = fp.Bits / 4 11 12 var ( 13 shiftPoint starkcurve.G1Jac 14 pointIndexed [4][nibbleCount][16]*starkcurve.G1Jac 15 p [4]starkcurve.G1Jac 16 ) 17 18 func init() { 19 // The curve points come from the [reference implementation]. 20 // 21 // [reference implementation]: https://github.com/starkware-libs/cairo-lang/blob/de741b92657f245a50caab99cfaef093152fd8be/src/starkware/crypto/signature/fast_pedersen_hash.py 22 23 shiftPoint.X.SetString("2089986280348253421170679821480865132823066470938446095505822317253594081284") 24 shiftPoint.Y.SetString("1713931329540660377023406109199410414810705867260802078187082345529207694986") 25 shiftPoint.Z.SetOne() 26 27 p[0].X.SetString("996781205833008774514500082376783249102396023663454813447423147977397232763") 28 p[0].Y.SetString("1668503676786377725805489344771023921079126552019160156920634619255970485781") 29 p[0].Z.SetOne() 30 31 p[1].X.SetString("2251563274489750535117886426533222435294046428347329203627021249169616184184") 32 p[1].Y.SetString("1798716007562728905295480679789526322175868328062420237419143593021674992973") 33 p[1].Z.SetOne() 34 35 p[2].X.SetString("2138414695194151160943305727036575959195309218611738193261179310511854807447") 36 p[2].Y.SetString("113410276730064486255102093846540133784865286929052426931474106396135072156") 37 p[2].Z.SetOne() 38 39 p[3].X.SetString("2379962749567351885752724891227938183011949129833673362440656643086021394946") 40 p[3].Y.SetString("776496453633298175483985398648758586525933812536653089401905292063708816422") 41 p[3].Z.SetOne() 42 43 var multiplier big.Int 44 for pointIndex, point := range p { 45 var nibbleIndexed [nibbleCount][16]*starkcurve.G1Jac 46 for nibIndex := uint(0); nibIndex < nibbleCount; nibIndex++ { 47 var selectorIndexed [16]*starkcurve.G1Jac 48 for selector := 0; selector < 16; selector++ { 49 multiplier.SetUint64(uint64(selector)) 50 multiplier.Lsh(&multiplier, nibIndex*4) 51 52 res := point 53 res.ScalarMultiplication(&res, &multiplier) 54 selectorIndexed[selector] = &res 55 } 56 nibbleIndexed[nibIndex] = selectorIndexed 57 } 58 pointIndexed[pointIndex] = nibbleIndexed 59 } 60 } 61 62 // PedersenArray implements [Pedersen array hashing]. 63 // 64 // [Pedersen array hashing]: https://docs.starknet.io/documentation/develop/Hashing/hash-functions/#array_hashing 65 func PedersenArray(elems ...*fp.Element) fp.Element { 66 var d fp.Element 67 for _, e := range elems { 68 d = Pedersen(&d, e) 69 } 70 return Pedersen(&d, new(fp.Element).SetUint64(uint64(len(elems)))) 71 } 72 73 // Pedersen implements the [Pedersen hash] based on the [reference implementation]. 74 // 75 // [Pedersen hash]: https://docs.starknet.io/documentation/develop/Hashing/hash-functions/#pedersen_hash 76 // [reference implementation]: https://github.com/starkware-libs/cairo-lang/blob/de741b92657f245a50caab99cfaef093152fd8be/src/starkware/crypto/signature/fast_pedersen_hash.py 77 func Pedersen(a *fp.Element, b *fp.Element) fp.Element { 78 acc := shiftPoint 79 accumulate := func(bytes []byte, nibbleIndexed [nibbleCount][16]*starkcurve.G1Jac) { 80 for i, val := range bytes { 81 lowNibble := val & 0x0F 82 index := len(bytes) - i - 1 83 84 if lowNibble > 0 { 85 lowNibbleIndex := 2 * index 86 acc.AddAssign(nibbleIndexed[lowNibbleIndex][lowNibble]) 87 } 88 89 highNibble := (val & 0xF0) >> 4 90 91 if highNibble > 0 { 92 highNibbleIndex := (2 * index) + 1 93 acc.AddAssign(nibbleIndexed[highNibbleIndex][highNibble]) 94 } 95 } 96 } 97 98 aBytes := a.Bytes() 99 accumulate(aBytes[1:], pointIndexed[0]) 100 accumulate(aBytes[:1], pointIndexed[1]) 101 bBytes := b.Bytes() 102 accumulate(bBytes[1:], pointIndexed[2]) 103 accumulate(bBytes[:1], pointIndexed[3]) 104 105 // recover the affine x coordinate 106 var x fp.Element 107 x.Inverse(&acc.Z). 108 Square(&x) 109 x.Mul(&acc.X, &x) 110 111 return x 112 }