go-ethereum/core/vm/privacy/ringct.go

640 lines
18 KiB
Go

package privacy
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/binary"
"errors"
"fmt"
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/crypto/secp256k1"
"github.com/XinFinOrg/XDPoSChain/log"
)
// These constants define the lengths of serialized public keys.
const (
PubKeyBytesLenCompressed = 33
PubKeyBytesLenUncompressed = 65
PubKeyBytesLenHybrid = 65
)
const (
pubkeyCompressed byte = 0x2 // y_bit + x coord
pubkeyUncompressed byte = 0x4 // x coord + y coord
pubkeyHybrid byte = 0x6 // y_bit + x coord + y coord
)
// The proof contains pretty much stuffs
// The proof contains pretty much stuffs
// Ring size rs: 1 byte => proof[0]
// num input: number of real inputs: 1 byte => proof[1]
// List of inputs/UTXO index typed uint64 => total size = rs * numInput * 8 = proof[0]*proof[1]*8
// List of key images: total size = numInput * 33 = proof[1] * 33
// number of output n: 1 byte
// List of output => n * 130 bytes
// transaction fee: uint256 => 32 byte
// ringCT proof size ctSize: uint16 => 2 byte
// ringCT proof: ctSize bytes
// bulletproofs: bp
type PrivateSendVerifier struct {
proof []byte
//ringCT RingCT
}
type Ring []*ecdsa.PublicKey
type RingSignature struct {
NumRing int
Size int // size of ring
M [32]byte // message
C *big.Int // ring signature value, 1 element
S [][]*big.Int // ring signature values: [NumRing][Size]
Ring []Ring // array of rings of pubkeys: [NumRing]
I []*ecdsa.PublicKey // key images, size = the number of rings [NumRing]
Curve elliptic.Curve
SerializedRing []byte //temporary memory stored the raw ring ct used in case of verifying ringCT with message verification
}
func isOdd(a *big.Int) bool {
return a.Bit(0) == 1
}
// SerializeCompressed serializes a public key in a 33-byte compressed format.
func SerializeCompressed(p *ecdsa.PublicKey) []byte {
b := make([]byte, 0, PubKeyBytesLenCompressed)
format := pubkeyCompressed
if isOdd(p.Y) {
format |= 0x1
}
b = append(b, format)
return append(b, PadTo32Bytes(p.X.Bytes())...)
}
func DeserializeCompressed(curve elliptic.Curve, b []byte) *ecdsa.PublicKey {
x := new(big.Int).SetBytes(b[1:33])
// Y = +-sqrt(x^3 + B)
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)
x3.Add(x3, curve.Params().B)
// now calculate sqrt mod p of x2 + B
// This code used to do a full sqrt based on tonelli/shanks,
// but this was replaced by the algorithms referenced in
// https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294
PPlus1Div4 := new(big.Int).Add(curve.Params().P, big.NewInt(1))
PPlus1Div4.Rsh(PPlus1Div4, 2)
y := new(big.Int).Exp(x3, PPlus1Div4, curve.Params().P)
ybit := b[0]%2 == 1
if ybit != isOdd(y) {
y.Sub(curve.Params().P, y)
}
if ybit != isOdd(y) {
return nil
}
return &ecdsa.PublicKey{
Curve: curve,
X: x,
Y: y,
}
}
// bytes returns the public key ring as a byte slice.
func (r Ring) Bytes() (b []byte) {
for _, pub := range r {
b = append(b, PadTo32Bytes(pub.X.Bytes())...)
b = append(b, PadTo32Bytes(pub.Y.Bytes())...)
}
return
}
func PadTo32Bytes(in []byte) []byte {
padded := make([]byte, 32)
if len(in) >= 32 {
copy(padded, in)
} else {
copy(padded[32-len(in):], in)
}
return padded
}
// converts the signature to a byte array
// this is the format that will be used when passing EVM bytecode
func (r *RingSignature) Serialize() ([]byte, error) {
sig := []byte{}
// add size and message
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(r.NumRing))
sig = append(sig, b[:]...) // 8 bytes
b = make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(r.Size))
sig = append(sig, b[:]...) // 8 bytes
sig = append(sig, PadTo32Bytes(r.M[:])...) // 32 bytes
sig = append(sig, PadTo32Bytes(r.C.Bytes())...) // 32 bytes
for k := 0; k < r.NumRing; k++ {
// 96 bytes each iteration
for i := 0; i < r.Size; i++ {
sig = append(sig, PadTo32Bytes(r.S[k][i].Bytes())...)
}
}
for k := 0; k < r.NumRing; k++ {
// 96 bytes each iteration
for i := 0; i < r.Size; i++ {
rb := SerializeCompressed(r.Ring[k][i])
sig = append(sig, rb...)
}
}
for k := 0; k < r.NumRing; k++ {
// 64 bytes
rb := SerializeCompressed(r.I[k])
sig = append(sig, rb...)
}
if len(sig) != 8+8+32+32+(32+33)*r.NumRing*r.Size+33*r.NumRing {
return []byte{}, errors.New("could not serialize ring signature")
}
return sig, nil
}
func computeSignatureSize(numRing int, ringSize int) int {
const MaxInt = int(^uint(0) >> 1)
if numRing < 0 || ringSize < 0 {
return -1
}
// Calculate term and check for overflow
term := numRing * ringSize * 65
if term < 0 || term < numRing || term < ringSize {
return -1
}
return 8 + 8 + 32 + 32 + numRing*ringSize*32 + numRing*ringSize*33 + numRing*33
}
// deserializes the byteified signature into a RingSignature struct
func Deserialize(r []byte) (*RingSignature, error) {
if len(r) < 16 {
return nil, errors.New("failed to deserialize ring signature")
}
offset := 0
sig := new(RingSignature)
numRing := r[offset : offset+8]
offset += 8
size := r[offset : offset+8]
offset += 8
size_uint := binary.BigEndian.Uint64(size)
size_int := int(size_uint)
sig.Size = size_int
size_uint = binary.BigEndian.Uint64(numRing)
size_int = int(size_uint)
sig.NumRing = size_int
if len(r) != computeSignatureSize(sig.NumRing, sig.Size) {
return nil, fmt.Errorf("incorrect ring size, len r: %d, sig.NumRing: %d sig.Size: %d", len(r), sig.NumRing, sig.Size)
}
m := r[offset : offset+32]
offset += 32
var m_byte [32]byte
copy(m_byte[:], m)
sig.M = m_byte
sig.C = new(big.Int).SetBytes(r[offset : offset+32])
offset += 32
sig.S = make([][]*big.Int, sig.NumRing)
for i := 0; i < sig.NumRing; i++ {
sig.S[i] = make([]*big.Int, sig.Size)
for j := 0; j < sig.Size; j++ {
sig.S[i][j] = new(big.Int).SetBytes(r[offset : offset+32])
offset += 32
}
}
sig.Curve = crypto.S256()
sig.Ring = make([]Ring, sig.NumRing)
for i := 0; i < sig.NumRing; i++ {
sig.Ring[i] = make([]*ecdsa.PublicKey, sig.Size)
for j := 0; j < sig.Size; j++ {
compressedKey := r[offset : offset+33]
offset += 33
compressedPubKey := DeserializeCompressed(sig.Curve, compressedKey)
sig.Ring[i][j] = compressedPubKey
}
}
sig.I = make([]*ecdsa.PublicKey, sig.NumRing)
for i := 0; i < sig.NumRing; i++ {
compressedKey := r[offset : offset+33]
offset += 33
compressedPubKey := DeserializeCompressed(sig.Curve, compressedKey)
sig.I[i] = compressedPubKey
}
sig.SerializedRing = r
if !Verify(sig, false) {
return nil, errors.New("failed to deserialize, invalid ring signature")
}
return sig, nil
}
// takes public key ring and places the public key corresponding to `privkey` in index s of the ring
// returns a key ring of type []*ecdsa.PublicKey
func GenKeyRing(ring []*ecdsa.PublicKey, privkey *ecdsa.PrivateKey, s int) ([]*ecdsa.PublicKey, error) {
size := len(ring) + 1
new_ring := make([]*ecdsa.PublicKey, size)
pubkey := privkey.Public().(*ecdsa.PublicKey)
if s > len(ring) {
return nil, errors.New("index s out of bounds")
}
new_ring[s] = pubkey
for i := 1; i < size; i++ {
idx := (i + s) % size
new_ring[idx] = ring[i-1]
}
return new_ring, nil
}
// creates a ring with size specified by `size` and places the public key corresponding to `privkey` in index s of the ring
// returns a new key ring of type []*ecdsa.PublicKey
func GenNewKeyRing(size int, privkey *ecdsa.PrivateKey, s int) ([]*ecdsa.PublicKey, error) {
ring := make([]*ecdsa.PublicKey, size)
pubkey := privkey.Public().(*ecdsa.PublicKey)
if s >= len(ring) {
return nil, errors.New("index s out of bounds")
}
ring[s] = pubkey
for i := 1; i < size; i++ {
idx := (i + s) % size
priv, err := crypto.GenerateKey()
if err != nil {
return nil, err
}
pub := priv.Public()
ring[idx] = pub.(*ecdsa.PublicKey)
}
return ring, nil
}
// calculate key image I = x * H_p(P) where H_p is a hash function that returns a point
// H_p(P) = sha3(P) * G
func GenKeyImage(privkey *ecdsa.PrivateKey) *ecdsa.PublicKey {
pubkey := privkey.Public().(*ecdsa.PublicKey)
image := new(ecdsa.PublicKey)
// calculate sha3(P)
h_x, h_y := HashPoint(pubkey)
// calculate H_p(P) = x * sha3(P) * G
i_x, i_y := privkey.Curve.ScalarMult(h_x, h_y, privkey.D.Bytes())
image.X = i_x
image.Y = i_y
return image
}
func HashPoint(p *ecdsa.PublicKey) (*big.Int, *big.Int) {
input := append(PadTo32Bytes(p.X.Bytes()), PadTo32Bytes(p.Y.Bytes())...)
log.Info("HashPoint", "input ", common.Bytes2Hex(input))
hash := crypto.Keccak256(input)
log.Info("HashPoint", "hash ", common.Bytes2Hex(hash))
return p.Curve.ScalarBaseMult(hash[:])
}
// create ring signature from list of public keys given inputs:
// msg: byte array, message to be signed
// ring: array of *ecdsa.PublicKeys to be included in the ring
// privkey: *ecdsa.PrivateKey of signer
// s: index of signer in ring
func Sign(m [32]byte, rings []Ring, privkeys []*ecdsa.PrivateKey, s int) (*RingSignature, error) {
numRing := len(rings)
if numRing < 1 {
return nil, errors.New("there is no ring to make signature")
}
// check ringsize > 1
ringsize := len(rings[0])
if ringsize < 2 {
return nil, errors.New("size of ring less than two")
} else if s >= ringsize || s < 0 {
return nil, errors.New("secret index out of range of ring size")
}
// setup
//pubkey := privkey.Public().(*ecdsa.PublicKey)
pubkeys := make([]*ecdsa.PublicKey, numRing)
for i := 0; i < numRing; i++ {
pubkeys[i] = &privkeys[i].PublicKey
}
//cast to BitCurve used in go-eth since elliptic.Curve.Add() and elliptic.Curve.ScalarMult() is deprecated
curve := pubkeys[0].Curve.(*secp256k1.BitCurve)
sig := new(RingSignature)
sig.Size = ringsize
sig.NumRing = numRing
sig.M = m
sig.Ring = rings
sig.Curve = curve
// check that key at index s is indeed the signer
for i := 0; i < numRing; i++ {
if rings[i][s] != pubkeys[i] {
return nil, errors.New("secret index in ring is not signer")
}
}
// generate key image
images := make([]*ecdsa.PublicKey, numRing)
for i := 0; i < numRing; i++ {
images[i] = GenKeyImage(privkeys[i])
}
sig.I = images
// start at c[1]
// pick random scalar u (glue value), calculate c[1] = H(m, u*G) where H is a hash function and G is the base point of the curve
C := make([]*big.Int, ringsize)
S := make([][]*big.Int, numRing)
for i := 0; i < numRing; i++ {
S[i] = make([]*big.Int, ringsize)
}
//Initialize S except S[..][s]
for i := 0; i < numRing; i++ {
for j := 0; j < ringsize; j++ {
if j != s {
randomGenerated, err := rand.Int(rand.Reader, curve.Params().P)
if err != nil {
return nil, err
}
S[i][j] = randomGenerated
}
}
}
L := make([][]*ecdsa.PublicKey, numRing)
R := make([][]*ecdsa.PublicKey, numRing)
for i := 0; i < numRing; i++ {
L[i] = make([]*ecdsa.PublicKey, ringsize)
R[i] = make([]*ecdsa.PublicKey, ringsize)
}
alpha := make([]*big.Int, numRing)
var l []byte
//compute L[i][s], R[i][s], i = 0..numRing
for i := 0; i < numRing; i++ {
randomGenerated, err := rand.Int(rand.Reader, curve.Params().P)
if err != nil {
return nil, err
}
alpha[i] = randomGenerated
// start at secret index s/PI
// compute L_s = u*G
l_x, l_y := curve.ScalarBaseMult(PadTo32Bytes(alpha[i].Bytes()))
L[i][s] = &ecdsa.PublicKey{
Curve: curve,
X: l_x,
Y: l_y,
}
lT := append(PadTo32Bytes(l_x.Bytes()), PadTo32Bytes(l_y.Bytes())...)
l = append(l, lT...)
// compute R_s = u*H_p(P[s])
h_x, h_y := HashPoint(pubkeys[i])
r_x, r_y := curve.ScalarMult(h_x, h_y, PadTo32Bytes(alpha[i].Bytes()))
R[i][s] = &ecdsa.PublicKey{
Curve: curve,
X: r_x,
Y: r_y,
}
rT := append(PadTo32Bytes(r_x.Bytes()), PadTo32Bytes(r_y.Bytes())...)
l = append(l, rT...)
}
// concatenate m and u*G and calculate c[s+1] = H(m, L_s, R_s)
C_j := crypto.Keccak256(append(m[:], l...))
idx := s + 1
if idx == ringsize {
idx = 0
}
if idx == 0 {
C[0] = new(big.Int).SetBytes(C_j[:])
} else {
C[idx] = new(big.Int).SetBytes(C_j[:])
}
for idx != s {
var l []byte
for j := 0; j < numRing; j++ {
// calculate L[j][idx] = s[j][idx]*G + c[idx]*Ring[j][idx]
px, py := curve.ScalarMult(rings[j][idx].X, rings[j][idx].Y, PadTo32Bytes(C[idx].Bytes())) // px, py = c_i*P_i
sx, sy := curve.ScalarBaseMult(PadTo32Bytes(S[j][idx].Bytes())) // sx, sy = s[n-1]*G
if px == nil || py == nil || sx == nil || sy == nil {
return nil, errors.New("could not create ring signature")
}
l_x, l_y := curve.Add(sx, sy, px, py)
L[j][idx] = &ecdsa.PublicKey{
Curve: curve,
X: l_x,
Y: l_y,
}
lT := append(PadTo32Bytes(l_x.Bytes()), PadTo32Bytes(l_y.Bytes())...)
l = append(l, lT...)
// calculate R[j][idx] = s[j][idx]*H_p(Ring[j][idx]) + c[idx]*I[j]
px, py = curve.ScalarMult(images[j].X, images[j].Y, C[idx].Bytes()) // px, py = c_i*I
hx, hy := HashPoint(rings[j][idx])
sx, sy = curve.ScalarMult(hx, hy, S[j][idx].Bytes()) // sx, sy = s[n-1]*H_p(P_i)
if px == nil || py == nil || sx == nil || sy == nil {
return nil, errors.New("could not create ring signature")
}
r_x, r_y := curve.Add(sx, sy, px, py)
R[j][idx] = &ecdsa.PublicKey{
Curve: curve,
X: r_x,
Y: r_y,
}
rT := append(PadTo32Bytes(r_x.Bytes()), PadTo32Bytes(r_y.Bytes())...)
l = append(l, rT...)
}
idx++
if idx == ringsize {
idx = 0
}
var ciIdx int
if idx == 0 {
ciIdx = 0
} else {
ciIdx = idx
}
cSha := crypto.Keccak256(append(PadTo32Bytes(m[:]), l...))
C[ciIdx] = new(big.Int).SetBytes(cSha[:])
}
//compute S[j][s] = alpha[j] - c[s] * privkeys[j], privkeys[j] = private key corresponding to key image I[j]
for j := 0; j < numRing; j++ {
cx := C[s]
// close ring by finding S[j][s] = (alpha[j] - c[s]*privkeys[s] ) mod P where k[s] is the private key and P is the order of the curve
S[j][s] = new(big.Int).Mod(new(big.Int).Sub(alpha[j], new(big.Int).Mul(cx, privkeys[j].D)), curve.Params().N)
}
// everything ok, add values to signature
sig.S = S
sig.C = C[0]
sig.NumRing = numRing
sig.Size = ringsize
sig.C = C[0]
return sig, nil
}
// verify ring signature contained in RingSignature struct
// returns true if a valid signature, false otherwise
func Verify(sig *RingSignature, verifyMes bool) bool {
// setup
rings := sig.Ring
ringsize := sig.Size
numRing := sig.NumRing
S := sig.S
C := make([]*big.Int, ringsize+1)
C[0] = sig.C
//cast to BitCurve used in go-eth since elliptic.Curve.Add() and elliptic.Curve.ScalarMult() is deprecated
curve := sig.Curve.(*secp256k1.BitCurve)
image := sig.I
//check on curve
for i := 0; i < numRing; i++ {
onCurve := curve.IsOnCurve(image[i].X, image[i].Y)
if !onCurve {
return false
}
for j := 0; j < ringsize; j++ {
onCurve := curve.IsOnCurve(rings[i][j].X, rings[i][j].Y)
if !onCurve {
return false
}
}
}
// calculate c[i+1] = H(m, s[i]*G + c[i]*P[i])
// and c[0] = H)(m, s[n-1]*G + c[n-1]*P[n-1]) where n is the ring size
//log.Info("C", "0", common.Bytes2Hex(C[0].Bytes()))
for j := 0; j < ringsize; j++ {
var l []byte
for i := 0; i < numRing; i++ {
// Validate S[i][j] and C[j]
if !isValidScalar(S[i][j], curve) || !isValidScalar(C[j], curve) {
return false // Or handle the error as required
}
// calculate L[i][j] = s[i][j]*G + c[j]*Ring[i][j]
px, py := curve.ScalarMult(rings[i][j].X, rings[i][j].Y, C[j].Bytes()) // px, py = c_i*P_i
sx, sy := curve.ScalarBaseMult(S[i][j].Bytes()) // sx, sy = s[i]*G
if px == nil || py == nil || sx == nil || sy == nil {
return false
}
l_x, l_y := curve.Add(sx, sy, px, py)
lT := append(PadTo32Bytes(l_x.Bytes()), PadTo32Bytes(l_y.Bytes())...)
//log.Info("L[i][j]", "i", i, "j", j, "L", common.Bytes2Hex(lT))
l = append(l, lT...)
// calculate R_i = s[i][j]*H_p(Ring[i][j]) + c[j]*I[j]
px, py = curve.ScalarMult(image[i].X, image[i].Y, C[j].Bytes()) // px, py = c[i]*I
hx, hy := HashPoint(rings[i][j])
// Validate S[i][j], hx, and hy
if !isValidScalar(S[i][j], curve) || !isValidScalar(hx, curve) || !isValidScalar(hy, curve) {
return false // Or handle the error as required
}
//log.Info("H[i][j]", "i", i, "j", j, "x.input", common.Bytes2Hex(rings[i][j].X.Bytes()), "y.input", common.Bytes2Hex(rings[i][j].Y.Bytes()))
//log.Info("H[i][j]", "i", i, "j", j, "x", common.Bytes2Hex(hx.Bytes()), "y", common.Bytes2Hex(hy.Bytes()))
sx, sy = curve.ScalarMult(hx, hy, S[i][j].Bytes()) // sx, sy = s[i]*H_p(P[i])
if px == nil || py == nil || sx == nil || sy == nil {
return false
}
r_x, r_y := curve.Add(sx, sy, px, py)
rT := append(PadTo32Bytes(r_x.Bytes()), PadTo32Bytes(r_y.Bytes())...)
//log.Info("R[i][j]", "i", i, "j", j, "L", common.Bytes2Hex(rT))
l = append(l, rT...)
}
// calculate c[i+1] = H(m, L_i, R_i)
//cj_mes := append(PadTo32Bytes(sig.M[:]), l...)
C_j := crypto.Keccak256(append(PadTo32Bytes(sig.M[:]), l...))
//log.Info("C hash input", "j", j + 1, "C_input", common.Bytes2Hex(cj_mes))
/*if j == ringsize-1 {
C[0] = new(big.Int).SetBytes(C_j[:])
} else {*/
C[j+1] = new(big.Int).SetBytes(C_j[:])
//log.Info("C", "j", j + 1, "C", common.Bytes2Hex(C[j + 1].Bytes()))
//}
}
return bytes.Equal(sig.C.Bytes(), C[ringsize].Bytes())
}
func isValidScalar(scalar *big.Int, curve elliptic.Curve) bool {
return scalar.Sign() >= 0 && scalar.Cmp(curve.Params().N) < 0
}
func Link(sig_a *RingSignature, sig_b *RingSignature) bool {
for i := 0; i < len(sig_a.I); i++ {
for j := 0; j < len(sig_b.I); j++ {
if sig_a.I[i].X == sig_b.I[j].X && sig_a.I[i].Y == sig_b.I[j].Y {
return true
}
}
}
return false
}
// function returns(mutiple rings, private keys, message, error)
func GenerateMultiRingParams(numRing int, ringSize int, s int) (rings []Ring, privkeys []*ecdsa.PrivateKey, m [32]byte, err error) {
for i := 0; i < numRing; i++ {
privkey, err := crypto.GenerateKey()
if err != nil {
return nil, nil, [32]byte{}, err
}
privkeys = append(privkeys, privkey)
ring, err := GenNewKeyRing(ringSize, privkey, s)
if err != nil {
return nil, nil, [32]byte{}, err
}
rings = append(rings, ring)
}
_, err = rand.Read(m[:])
if err != nil {
return nil, nil, [32]byte{}, err
}
return rings, privkeys, m, nil
}