This repository has been archived on 2024-04-07. You can view files and clone it, but cannot push or open issues or pull requests.
moneroutil/ringsignature.go
2017-05-11 12:15:06 -07:00

237 lines
5.7 KiB
Go

package moneroutil
import (
"fmt"
"io"
"math/rand"
)
type RingSignatureElement struct {
c [ScalarLength]byte
r [ScalarLength]byte
}
type RingSignature []*RingSignatureElement
func (r *RingSignatureElement) Serialize() (result []byte) {
result = make([]byte, 2*ScalarLength)
copy(result[:ScalarLength], r.c[:])
copy(result[ScalarLength:2*ScalarLength], r.r[:])
return
}
func (r *RingSignature) Serialize() (result []byte) {
result = make([]byte, len(*r)*ScalarLength*2)
for i := 0; i < len(*r); i++ {
copy(result[i*ScalarLength*2:(i+1)*ScalarLength*2], (*r)[i].Serialize())
}
return
}
func ParseSignature(buf io.Reader) (result *RingSignatureElement, err error) {
rse := new(RingSignatureElement)
c := make([]byte, ScalarLength)
n, err := buf.Read(c)
if err != nil {
return
}
if n != ScalarLength {
err = fmt.Errorf("Not enough bytes for signature c")
return
}
copy(rse.c[:], c)
r := make([]byte, ScalarLength)
n, err = buf.Read(r)
if err != nil {
return
}
if n != ScalarLength {
err = fmt.Errorf("Not enough bytes for signature r")
return
}
copy(rse.r[:], r)
result = rse
return
}
func ParseSignatures(mixinLengths []int, buf io.Reader) (signatures []RingSignature, err error) {
// mixinLengths is the number of mixins at each input position
sigs := make([]RingSignature, len(mixinLengths), len(mixinLengths))
for i, nMixin := range mixinLengths {
sigs[i] = make([]*RingSignatureElement, nMixin, nMixin)
for j := 0; j < nMixin; j++ {
sigs[i][j], err = ParseSignature(buf)
if err != nil {
return
}
}
}
signatures = sigs
return
}
func HashToScalar(data ...[]byte) (result [ScalarLength]byte) {
result = Keccak256(data...)
ScReduce32(&result)
return
}
func CreateSignature(prefixHash *Hash, mixins []PubKey, privKey *PrivKey) (keyImage PubKey, pubKeys []PubKey, sig RingSignature) {
point := privKey.PubKey().HashToEC()
privKeyBytes := privKey.ToBytes()
keyImagePoint := new(ProjectiveGroupElement)
GeScalarMult(keyImagePoint, &privKeyBytes, point)
var keyImageBytes [PointLength]byte
// convert key Image point from Projective to Extended
// in order to precompute
keyImagePoint.ToBytes(&keyImageBytes)
keyImageGe := new(ExtendedGroupElement)
keyImageGe.FromBytes(&keyImageBytes)
keyImage = PubKey(keyImageBytes)
var keyImagePre [8]CachedGroupElement
GePrecompute(&keyImagePre, keyImageGe)
k := RandomScalar()
pubKeys = make([]PubKey, len(mixins)+1)
privIndex := rand.Intn(len(pubKeys))
pubKeys[privIndex] = *privKey.PubKey()
r := make([]*RingSignatureElement, len(pubKeys))
var sum [ScalarLength]byte
toHash := prefixHash[:]
for i := 0; i < len(pubKeys); i++ {
tmpE := new(ExtendedGroupElement)
tmpP := new(ProjectiveGroupElement)
var tmpEBytes, tmpPBytes [PointLength]byte
if i == privIndex {
GeScalarMultBase(tmpE, &k)
tmpE.ToBytes(&tmpEBytes)
toHash = append(toHash, tmpEBytes[:]...)
tmpE = privKey.PubKey().HashToEC()
GeScalarMult(tmpP, &k, tmpE)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
} else {
if i > privIndex {
pubKeys[i] = mixins[i-1]
} else {
pubKeys[i] = mixins[i]
}
r[i] = &RingSignatureElement{
c: RandomScalar(),
r: RandomScalar(),
}
pubKeyBytes := pubKeys[i].ToBytes()
tmpE.FromBytes(&pubKeyBytes)
GeDoubleScalarMultVartime(tmpP, &r[i].c, tmpE, &r[i].r)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
tmpE = pubKeys[i].HashToEC()
GeDoubleScalarMultPrecompVartime(tmpP, &r[i].r, tmpE, &r[i].c, &keyImagePre)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
ScAdd(&sum, &sum, &r[i].c)
}
}
h := HashToScalar(toHash)
r[privIndex] = new(RingSignatureElement)
ScSub(&r[privIndex].c, &h, &sum)
scalar := privKey.ToBytes()
ScMulSub(&r[privIndex].r, &r[privIndex].c, &scalar, &k)
sig = r
return
}
func VerifySignature(prefixHash *Hash, keyImage *PubKey, pubKeys []PubKey, ringSignature RingSignature) (result bool) {
keyImageGe := new(ExtendedGroupElement)
keyImageBytes := [PointLength]byte(*keyImage)
if !keyImageGe.FromBytes(&keyImageBytes) {
result = false
return
}
var keyImagePre [8]CachedGroupElement
GePrecompute(&keyImagePre, keyImageGe)
toHash := prefixHash[:]
var tmpS, sum [ScalarLength]byte
for i, pubKey := range pubKeys {
rse := ringSignature[i]
if !ScValid(&rse.c) || !ScValid(&rse.r) {
result = false
return
}
tmpE := new(ExtendedGroupElement)
tmpP := new(ProjectiveGroupElement)
pubKeyBytes := [PointLength]byte(pubKey)
if !tmpE.FromBytes(&pubKeyBytes) {
result = false
return
}
var tmpPBytes, tmpEBytes [PointLength]byte
GeDoubleScalarMultVartime(tmpP, &rse.c, tmpE, &rse.r)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
tmpE = pubKey.HashToEC()
tmpE.ToBytes(&tmpEBytes)
GeDoubleScalarMultPrecompVartime(tmpP, &rse.r, tmpE, &rse.c, &keyImagePre)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
ScAdd(&sum, &sum, &rse.c)
}
tmpS = HashToScalar(toHash)
ScSub(&sum, &tmpS, &sum)
result = ScIsZero(&sum)
return
}
/* Below are structs for the CT version */
type Key [32]byte
type ctKey struct {
destination Key
mask Key
}
type ecdhTuple struct {
mask Key
amount Key
senderPk Key
}
type RingSignatureBase struct {
ringSigType uint8
message Key
mixRing [][]ctKey
pseudoOuts []Key
ecdhInfo []ecdhTuple
outPk []ctKey
fee uint64
}
type Key64 [64]Key
type boroSig struct {
s0 Key64
s1 Key64
ee Key
}
type mgSig struct {
ss [][]Key
cc Key
ii []Key
}
type rangeSig struct {
asig boroSig
ci Key64
}
type RctSigPrunable struct {
rangeSigs []rangeSig
MGs []mgSig
}
type RingSignatureCT struct {
RingSignatureBase
RctSigPrunable
}