package hamcrypto // Trinary SWIFFT hash for the Gnarl scheme. // Ring: Z_271[x]/(x^27 + 1), n=27, m=12. import "crypto/rand" const ( GnarlM = 12 GnarlInputBits = GnarlM * GnarlN gnarlInputBytes = (GnarlInputBits + 7) / 8 GnarlHashBits = GnarlN * 9 GnarlHashBytes = (GnarlHashBits + 7) / 8 GnarlMidBits = GnarlN * 8 GnarlMidBytes = GnarlMidBits / 8 GnarlShardBits = GnarlN * 2 GnarlShardBytes = (GnarlShardBits + 7) / 8 GnarlMidR = 243 GnarlShardR = 3 ) type GnarlHash [GnarlHashBytes]byte type GnarlMid [GnarlMidBytes]byte type GnarlShard [GnarlShardBytes]byte var gnarlKeys [GnarlM][GnarlN]uint16 const gnarlBasisPad = 32 var gnarlKeyBasis [GnarlM][GnarlN][gnarlBasisPad]uint16 func initGnarlKeys() { seed := uint64(0) seedStr := "gnarl-hamadryad-v1-dendrite-trinary" for i := int32(0); i < int32(len(seedStr)); i++ { seed ^= uint64(seedStr[i]) << ((uint(i) * 7) % 64) } xorshift := func() (v uint64) { seed ^= seed << 13 seed ^= seed >> 7 seed ^= seed << 17 return seed } for i := int32(0); i < GnarlM; i++ { var poly [GnarlN]uint16 for j := int32(0); j < GnarlN; j++ { poly[j] = uint16(xorshift() % uint64(GnarlP)) } ntt27(&poly) gnarlKeys[i] = poly } // Precompute basis tables. for i := int32(0); i < GnarlM; i++ { for k := int32(0); k < GnarlN; k++ { var ek [GnarlN]uint16 ek[k] = 1 ntt27(&ek) for j := int32(0); j < GnarlN; j++ { gnarlKeyBasis[i][k][j] = mod271(uint32(gnarlKeys[i][j]) * uint32(ek[j])) } } } } // gnarlCompress computes one SWIFFT compression: 41 bytes -> 27 coefficients in Z_271. func gnarlCompress(block *[gnarlInputBytes]byte) (result [GnarlN]uint16) { var acc [gnarlBasisPad]uint32 gnarlAccumulate(&acc, &gnarlKeyBasis, block) for j := int32(0); j < GnarlN; j++ { result[j] = mod271(acc[j]) } intt27(&result) return result } // gnarlAccumulate scans bits in block and accumulates basis table rows. func gnarlAccumulate(acc *[gnarlBasisPad]uint32, basis *[GnarlM][GnarlN][gnarlBasisPad]uint16, block *[gnarlInputBytes]byte) { for i := int32(0); i < GnarlM; i++ { bitBase := i * GnarlN for k := int32(0); k < GnarlN; k++ { bitIdx := bitBase + k byteIdx := bitIdx / 8 bitOff := uint(bitIdx % 8) if byteIdx < gnarlInputBytes && block[byteIdx]&(1<>8), byte(msgLenBits>>16), byte(msgLenBits>>24), byte(msgLenBits>>32), byte(msgLenBits>>40), byte(msgLenBits>>48), byte(msgLenBits>>56), ) off := int32(0) for off < int32(len(padded)) { var block [gnarlInputBytes]byte copy(block[:], padded[off:off+gnarlInputBytes]) result := gnarlCompress(&block) for j := int32(0); j < GnarlN; j++ { chain[j] = mod271(uint32(chain[j]) + uint32(result[j])) } off += gnarlInputBytes } return chain } // GHash computes the 243-bit GnarlHash of an arbitrary-length message. func GHash(msg []byte) (h GnarlHash) { coeffs := gnarlHashCore(msg) return packCoeffs243(coeffs) } // GMid computes the 216-bit GnarlMid of an arbitrary-length message. func GMid(msg []byte) (m GnarlMid) { coeffs := gnarlHashCore(msg) return packCoeffs216(coeffs) } // GShard computes the 54-bit GnarlShard of an arbitrary-length message. func GShard(msg []byte) (s GnarlShard) { coeffs := gnarlHashCore(msg) return packCoeffs54(coeffs) } // Mid extracts the GnarlMid tier from a full GnarlHash. func (h *GnarlHash) Mid() (m GnarlMid) { coeffs := unpackCoeffs243(*h) return packCoeffs216(coeffs) } // Shard extracts the GnarlShard tier from a full GnarlHash. func (h *GnarlHash) Shard() (s GnarlShard) { coeffs := unpackCoeffs243(*h) return packCoeffs54(coeffs) } func (h *GnarlHash) IsZero() (result bool) { for i := int32(0); i < GnarlHashBytes; i++ { if h[i] != 0 { return false } } return true } func (m *GnarlMid) IsZero() (result bool) { for i := int32(0); i < GnarlMidBytes; i++ { if m[i] != 0 { return false } } return true } func (s *GnarlShard) IsZero() (result bool) { for i := int32(0); i < GnarlShardBytes; i++ { if s[i] != 0 { return false } } return true } // Sum returns coefficient-wise sum (mod 271) of two GnarlHash values. func (h *GnarlHash) Sum(other *GnarlHash) (result GnarlHash) { a := unpackCoeffs243(*h) b := unpackCoeffs243(*other) var res [GnarlN]uint16 for i := int32(0); i < GnarlN; i++ { res[i] = mod271(uint32(a[i]) + uint32(b[i])) } return packCoeffs243(res) } // RandomGnarlHash generates a cryptographically random GnarlHash value. func RandomGnarlHash() (h GnarlHash) { _, err := rand.Read(h[:]) if err != nil { panic("crypto/rand failed") } h[GnarlHashBytes-1] &= 0x07 return h }