You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
7.5 KiB

package ringct
import "fmt"
import "github.com/deroproject/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
}