github.com/consensys/gnark-crypto@v0.14.0/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl (about)

     1  import (
     2  	"errors"
     3  	"hash"
     4  
     5  	"math/big"
     6  	"github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr"
     7  	"golang.org/x/crypto/sha3"
     8  	"sync"
     9  )
    10  
    11  const (
    12  {{ if eq .Name "bn254" }}
    13  	mimcNbRounds = 110
    14  {{- else if eq .Name "bls12-381"}}
    15  	mimcNbRounds = 111
    16  {{- else if eq .Name "bls12-377"}}
    17  	mimcNbRounds = 62
    18  {{- else if or (eq .Name "bls12-378") (eq .Name "bls24-315")}}
    19  	mimcNbRounds = 109
    20  {{- else if eq .Name "bls24-317"}}
    21  	mimcNbRounds = 91
    22  {{- else if eq .Name "bw6-633"}}
    23  	mimcNbRounds = 136
    24  {{- else if or (eq .Name "bw6-761") (eq .Name "bw6-756")}}
    25  	mimcNbRounds = 163
    26  {{- end}}
    27  	seed = "seed" 		 // seed to derive the constants
    28  	BlockSize = fr.Bytes // BlockSize size that mimc consumes
    29  )
    30  
    31  // Params constants for the mimc hash function
    32  var (
    33  	mimcConstants [mimcNbRounds]fr.Element
    34  	once sync.Once
    35  )
    36  
    37  
    38  
    39  // digest represents the partial evaluation of the checksum
    40  // along with the params of the mimc function
    41  type digest struct {
    42  	h      fr.Element
    43  	data   []fr.Element // data to hash
    44  	byteOrder fr.ByteOrder
    45  }
    46  
    47  // GetConstants exposed to be used in gnark
    48  func GetConstants() []big.Int {
    49  	once.Do(initConstants) // init constants
    50  	res := make([]big.Int, mimcNbRounds)
    51  	for i := 0; i < mimcNbRounds; i++ {
    52  		mimcConstants[i].BigInt(&res[i])
    53  	}
    54  	return res
    55  }
    56  
    57  // NewMiMC returns a MiMCImpl object, pure-go reference implementation
    58  func NewMiMC(opts ...Option) hash.Hash {
    59  	d := new(digest)
    60  	d.Reset()
    61  	cfg := mimcOptions(opts...)
    62  	d.byteOrder = cfg.byteOrder
    63  	return d
    64  }
    65  
    66  // Reset resets the Hash to its initial state.
    67  func (d *digest) Reset() {
    68  	d.data = d.data[:0]
    69  	d.h = fr.Element{0, 0, 0, 0}
    70  }
    71  
    72  // Sum appends the current hash to b and returns the resulting slice.
    73  // It does not change the underlying hash state.
    74  func (d *digest) Sum(b []byte) []byte {
    75  	buffer := d.checksum()
    76  	d.data = nil // flush the data already hashed
    77  	hash := buffer.Bytes()
    78  	b = append(b, hash[:]...)
    79  	return b
    80  }
    81  
    82  // BlockSize returns the hash's underlying block size.
    83  // The Write method must be able to accept any amount
    84  // of data, but it may operate more efficiently if all writes
    85  // are a multiple of the block size.
    86  func (d *digest) Size() int {
    87  	return BlockSize
    88  }
    89  
    90  // BlockSize returns the number of bytes Sum will return.
    91  func (d *digest) BlockSize() int {
    92  	return BlockSize
    93  }
    94  
    95  // Write (via the embedded io.Writer interface) adds more data to the running hash.
    96  //
    97  // Each []byte block of size BlockSize represents a big endian fr.Element.
    98  //
    99  // If len(p) is not a multiple of BlockSize and any of the []byte in p represent an integer
   100  // larger than fr.Modulus, this function returns an error.
   101  //
   102  // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first
   103  func (d *digest) Write(p []byte) (int, error) {
   104  	// we usually expect multiple of block size. But sometimes we hash short
   105  	// values (FS transcript). Instead of forcing to hash to field, we left-pad the
   106  	// input here.
   107  	if len(p) > 0 && len(p) < BlockSize {
   108  		pp := make([]byte,BlockSize)
   109  		copy(pp[len(pp)-len(p):], p)
   110  		p = pp
   111  	}
   112  
   113  	var start int
   114  	for start = 0; start < len(p); start += BlockSize {
   115  		if elem, err := d.byteOrder.Element((*[BlockSize]byte)(p[start:start+BlockSize])); err == nil {
   116  			d.data = append(d.data, elem)
   117  		} else {
   118  			return 0, err
   119  		}
   120  	}
   121  
   122  	if start != len(p) {
   123  		return 0, errors.New("invalid input length: must represent a list of field elements, expects a []byte of len m*BlockSize")
   124  	}
   125  	return len(p), nil
   126  }
   127  
   128  // Hash hash using Miyaguchi-Preneel:
   129  // https://en.wikipedia.org/wiki/One-way_compression_function
   130  // The XOR operation is replaced by field addition, data is in Montgomery form
   131  func (d *digest) checksum() fr.Element {
   132  	// Write guarantees len(data) % BlockSize == 0
   133  
   134  	// TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data?
   135  	// TODO: @Tabaie, @Thomas Piellard Now sure what to make of this
   136  	/*if len(d.data) == 0 {
   137  		d.data = make([]byte, BlockSize)
   138  	}*/
   139  
   140  	for i := range d.data {
   141  		r := d.encrypt(d.data[i])
   142  		d.h.Add(&r, &d.h).Add(&d.h, &d.data[i])
   143  	}
   144  
   145  	return d.h
   146  }
   147  
   148  
   149  {{ if eq .Name "bls12-377" }}
   150  // plain execution of a mimc run
   151  // m: message
   152  // k: encryption key
   153  func (d *digest) encrypt(m fr.Element) fr.Element {
   154  	once.Do(initConstants) // init constants
   155  
   156  	var tmp fr.Element
   157  	for i:=0; i < mimcNbRounds; i++ {
   158  		// m = (m+k+c)^**17
   159  		tmp.Add(&m, &d.h).Add(&tmp, &mimcConstants[i])
   160  		m.Square(&tmp).
   161  			Square(&m).
   162  			Square(&m).
   163  			Square(&m).
   164  			Mul(&m, &tmp)
   165  	}
   166  	m.Add(&m, &d.h)
   167  	return m
   168  }
   169  {{ else if eq .Name "bls24-317" }}
   170  // plain execution of a mimc run
   171  // m: message
   172  // k: encryption key
   173  func (d *digest) encrypt(m fr.Element) fr.Element {
   174  	once.Do(initConstants) // init constants
   175  
   176  	var tmp1, tmp2 fr.Element
   177  	for i := 0; i < mimcNbRounds; i++ {
   178  		// m = (m+k+c)^7
   179  		tmp1.Add(&m, &d.h).Add(&tmp1, &mimcConstants[i])
   180  		tmp2.Square(&tmp1)
   181  		m.Square(&tmp2).
   182  			Mul(&m, &tmp2).
   183  			Mul(&m, &tmp1)
   184  	}
   185  
   186  	m.Add(&m, &d.h)
   187  	return m
   188  }
   189  {{ else }}
   190  // plain execution of a mimc run
   191  // m: message
   192  // k: encryption key
   193  func (d *digest) encrypt(m fr.Element) fr.Element {
   194  	once.Do(initConstants) // init constants
   195  
   196  	var tmp fr.Element
   197  	for i := 0; i < mimcNbRounds; i++ {
   198  		// m = (m+k+c)^5
   199  		tmp.Add(&m, &d.h).Add(&tmp, &mimcConstants[i])
   200  		m.Square(&tmp).
   201  			Square(&m).
   202  			Mul(&m, &tmp)
   203  	}
   204  	m.Add(&m, &d.h)
   205  	return m
   206  }
   207  {{end}}
   208  
   209  // Sum computes the mimc hash of msg from seed
   210  func Sum(msg []byte) ([]byte, error) {
   211  	var d digest
   212  	if _, err := d.Write(msg); err != nil {
   213  		return nil, err
   214  	}
   215  	h := d.checksum()
   216  	bytes := h.Bytes()
   217  	return bytes[:], nil
   218  }
   219  
   220  
   221  func initConstants() {
   222  	bseed := ([]byte)(seed)
   223  
   224  	hash := sha3.NewLegacyKeccak256()
   225  	_, _ = hash.Write(bseed)
   226  	rnd := hash.Sum(nil) // pre hash before use
   227  	hash.Reset()
   228  	_, _ = hash.Write(rnd)
   229  
   230  	for i := 0; i < mimcNbRounds; i++ {
   231  		rnd = hash.Sum(nil)
   232  		mimcConstants[i].SetBytes(rnd)
   233  		hash.Reset()
   234  		_, _ = hash.Write(rnd)
   235  	}
   236  }
   237  
   238  // WriteString writes a string that doesn't necessarily consist of field elements
   239  func (d *digest) WriteString(rawBytes []byte) error {
   240  	if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil {
   241  		return err
   242  	} else {
   243  		d.data = append(d.data, elems[0])
   244  	}
   245  	return nil
   246  }