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  }