|
|
package ringct
import "fmt" import "github.com/arnaucode/derosuite/crypto"
// this file has license pending since it triggers a hard to find golang bug TODO add license after the golang bug is fixed
/* This file implements MLSAG signatures for the transactions */
// get the hash of the transaction which is used to create the mlsag later on, this hash is input to MLSAG
// the hash is = hash( message + hash(basehash) + hash(pederson and borromean data))
func Get_pre_mlsag_hash(sig *RctSig) crypto.Hash {
message_hash := sig.Message base_hash := crypto.Keccak256(sig.SerializeBase())
//fmt.Printf("Message hash %s\n", message_hash)
//fmt.Printf("Base hash %s\n", base_hash)
// now join the borromean signature and extract a sig
var other_data []byte for i := range sig.rangeSigs { //other_data = append(other_data,sig.rangeSigs[i].asig.s0.Serialize()...)
//other_data = append(other_data,sig.rangeSigs[i].asig.s1.Serialize()...)
//other_data = append(other_data,sig.rangeSigs[i].asig.ee[:]...)
//OR
// other_data = append(other_data, sig.rangeSigs[i].asig.Serialize()...) // serialise borrosig
// other_data = append(other_data, sig.rangeSigs[i].ci.Serialize()...)
// OR
other_data = append(other_data, sig.rangeSigs[i].Serialize()...) // range sig serialise
} other_data_hash := crypto.Keccak256(other_data)
//fmt.Printf("other hash %s\n", other_data_hash)
// join all 3 hashes and hash them again to get the data
final_data := append(message_hash[:], base_hash[:]...) final_data = append(final_data, other_data_hash[:]...) final_data_hash := crypto.Keccak256(final_data)
if DEBUGGING_MODE { fmt.Printf("final_data_hash hash %s\n", final_data_hash) }
return final_data_hash }
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
//This is a just slghtly more efficient version than the ones described below
//(will be explained in more detail in Ring Multisig paper
//These are aka MG signatutes in earlier drafts of the ring ct paper
// c.f. http://eprint.iacr.org/2015/1098 section 2.
// keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i
// Gen creates a signature which proves that for some column in the keymatrix "pk"
// the signer knows a secret key for each row in that column
// Ver verifies that the MG sig was created correctly
func MLSAG_Ver(message Key, pk [][]Key, rv *MlsagSig, dsRows int, r *RctSig) (result bool) { result = false cols := len(pk) if cols < 2 { if DEBUGGING_MODE { fmt.Printf("RingCT MLSAG_Ver must have cols > 1\n") } result = false return }
rows := len(pk[0]) if rows < 1 { if DEBUGGING_MODE { fmt.Printf("RingCT MLSAG_Ver must have rows > 0\n") } result = false return }
for i := 0; i < cols; i++ { if len(pk[i]) != rows { if DEBUGGING_MODE { fmt.Printf("RingCT MLSAG_Ver pk matrix not rectangular\n") } result = false return } }
if len(rv.II) != dsRows { if DEBUGGING_MODE { fmt.Printf("RingCT MLSAG_Ver Bad II size\n") } result = false return }
if len(rv.ss) != cols { if DEBUGGING_MODE { fmt.Printf("RingCT MLSAG_Ver Bad rv.ss size len(rv.ss) = %d cols = %d\n", len(rv.ss), cols) } result = false return }
for i := 0; i < cols; i++ { if len(rv.ss[i]) != rows { if DEBUGGING_MODE { fmt.Printf("RingCT MLSAG_Ver rv.ss is not rectangular\n") } result = false return } }
if dsRows > rows { if DEBUGGING_MODE { fmt.Printf("RingCT MLSAG_Ver Bad dsRows value\n") } result = false return }
for i := 0; i < len(rv.ss); i++ { for j := 0; j < len(rv.ss[i]); j++ { if !ScValid(&rv.ss[i][j]) { if DEBUGGING_MODE { fmt.Printf("RingCT MLSAG_Ver Bad ss slot\n") } result = false return } } }
if !ScValid(&rv.cc) { if DEBUGGING_MODE { fmt.Printf("RingCT MLSAG_Ver Bad r.cc slot\n") } result = false return }
Ip := make([][8]CachedGroupElement, dsRows, dsRows) // do pre computation of key keyImage
for i := 0; i < dsRows; i++ { key_image_point := new(ExtendedGroupElement) key_image_point.FromBytes(&rv.II[i]) GePrecompute(&Ip[i], key_image_point) }
ndsRows := 3 * dsRows //non Double Spendable Rows (see identity chains paper
toHash := make([]Key, 1+3*dsRows+2*(rows-dsRows), 1+3*dsRows+2*(rows-dsRows)) toHash[0] = message
// golang does NOT allow to use casts without using unsafe, so we can be slow but safe
toHash_bytes := make([]byte, 0, (1+3*dsRows+2*(rows-dsRows))*len(message))
var c Key c_old := rv.cc for i := 0; i < cols; i++ { Sc_0(&c) // zero out c
// BUG BUG BUG
// DERO project has found a go bug
// This bug affects all known golang supported platforms and architectures (arm/386/amd64/...?)
// even the golang 1.10 release candidates are affected ( though tip has not been tested )
//
// if you comment the line below and uncomment similiar line in first loop, the bug triggers for 1 in 20000 RCT full transactions, this means the the entire block chain cannot be verified before the bug fails the crypto
// this bug triggers at high probability when the affected code is executed by multiple goroutines simultaneously
// since the bug is notoriously hard to trigger while execution
// we have figured out an easy way to visibly demonstrate that the bug is present
// if the variables are declared within first loop, second loop is able to access them without declaring them
// this causes random memory to be used during CPU load, causing the transaction to fail since crypto checksums mark it as failure ( TODO detailed analysis)
// this bug may be the source of several other random crash bugs and need to be given a detailed looked
// this may be the source of the follown known but not-understood (cause not found) bugs
// https://github.com/golang/go/issues/15658
// https://github.com/golang/go/issues/20427
// https://github.com/golang/go/issues/22988
// https://github.com/golang/go/issues/20300 and even more
// NOTE: for golang developers, this bug needs to studied and fixed correctly. Since, another bug seems to exists
// which causes constants to flip ( yes consts ). However, we cannot be certain if its the same bug, once this gets quashed, we will test the other one too.
var L, R, Hi Key // comment this line and uncomment similiar line in first loop to trigger BUG
// first loop
for j := 0; j < dsRows; j++ { //var L, R, Hi Key // uncomment this line to trigger golang compiler BUG ( atleast on linux amd64)
AddKeys2(&L, &rv.ss[i][j], &c_old, &pk[i][j]) Hi = pk[i][j].HashToPoint() AddKeys3(&R, &rv.ss[i][j], &Hi, &c_old, &Ip[j])
toHash[3*j+1] = pk[i][j] toHash[3*j+2] = L toHash[3*j+3] = R }
//second loop
for j, ii := dsRows, 0; j < rows; j, ii = j+1, ii+1 { AddKeys2(&L, &rv.ss[i][j], &c_old, &pk[i][j]) // here L is getting used again
toHash[ndsRows+2*ii+1] = pk[i][j] toHash[ndsRows+2*ii+2] = L }
toHash_bytes = toHash_bytes[:0] // zero out everything
for k := range toHash { toHash_bytes = append(toHash_bytes, toHash[k][:]...) }
c = *(HashToScalar(toHash_bytes)) // hash_to_scalar(toHash);
copy(c_old[:], c[:]) // flipping the args here, will cause all transactions to become valid
}
if DEBUGGING_MODE { //fmt.Printf("c %x\n",c)
fmt.Printf("c_old %s\n", c_old) fmt.Printf("rv.ss %s\n", rv.cc) }
// c = c_old-rv.cc
ScSub(&c, &c_old, &rv.cc)
// if 0 checksum verified, otherwise checksum failed
result = ScIsZero(&c)
if DEBUGGING_MODE {
if result { fmt.Printf("RingCT MLSAG_Ver Success\n") } else { fmt.Printf("RingCT MLSAG_Ver verification failed\n") } }
return
}
|