In A World That Respects Privacy and Trust … Meet Blinded Signatures

The work of David Chaum on privacy showed the world that it could build a world of trust but preserve privacy. On the back of the work…

In A World That Respects Privacy and Trust … Meet Blinded Signatures

The work of David Chaum on privacy showed the world that it could build a world of trust but preserve privacy. On the back of the work around the ground-breaking RSA method, in 1983, David outlined [here][1]:

The paper outlined a blinded signature, and Bob can sign for a message without knowing what the message is. His method used RSA encryption, and where Bob creates his RSA keys in the usual way, and where he selects two prime numbers (p and q) and an encryption key value (e=63,535) and then computes:

Now Alice has a message (m) that she wants Bob to blind sign. She first generates a random value (k) and will then compute:

She sends this to Bob, and who uses his private key (d) to compute:

Bob sends this back, and Alice computes the true signature from Bob:

This is the signature that Bob would have signed the message with and as if Bob had used his private key:

This works because:

We can create an RSA key pair with the Bouncy Castle library with:

RsaKeyPairGenerator pGen = new RsaKeyPairGenerator();
pGen.Init(new KeyGenerationParameters(new SecureRandom(), s));
var pair = pGen.GenerateKeyPair();

Next, we can generate the blinding factor:

// "Blind" the signature 
PssSigner signer = new PssSigner(new RsaBlindingEngine(),
new Sha256Digest(), 20);

signer.Init(true, blindingParams);

signer.BlockUpdate(data, 0, data.Length);
byte[] sig = signer.GenerateSignature(); // get signature ready to sign

Next we can get the signer to sign the blinded message:

// Sign the blinded message
RsaEngine engine = new RsaEngine();
engine.Init(true, pair.Private);
var blindsign = engine.ProcessBlock(sig, 0, sig.Length);

Finally, we can then unblind the signature:

// Unblind signature
RsaBlindingEngine blindingEngine = new RsaBlindingEngine();
blindingEngine.Init(false, blindingParams);
byte[] signew = blindingEngine.ProcessBlock(blindsign, 0, blindsign.Length);

Finally, we can test the signature with the public key:

// Verify signature
signer = new PssSigner(new RsaEngine(), new Sha256Digest(), 20);
signer.Init(false,pair.Public);
signer.BlockUpdate(data, 0,data.Length);
var rtn=signer.VerifySignature(signew);

In this, blindsign is the blinded signature, and signnew is the unblinded version. The full code in C# is [here]:

namespace Blinded
{
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Generators;
using System.Text;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Signers;

class Program
{
public static byte[] getRandomBytes(int count) {
byte[] bytes = new byte[count];
new SecureRandom().NextBytes(bytes);
return bytes;
}

static void Main(string[] args)
{

string size="512";
string str="Hello";


if (args.Length >0) str=args[0];
if (args.Length >1) size=args[1];

int s = Convert.ToInt32(size);


try {

byte[] data = Encoding.ASCII.GetBytes(str);


RsaKeyPairGenerator pGen = new RsaKeyPairGenerator();

pGen.Init(new KeyGenerationParameters(new SecureRandom(), s));

var pair = pGen.GenerateKeyPair();


// Generate a blinding factor for public key
var blindingFactorGenerator = new RsaBlindingFactorGenerator();
blindingFactorGenerator.Init((RsaKeyParameters)pair.Public);

var blindingFactor = blindingFactorGenerator.GenerateBlindingFactor();


var blindingParams = new RsaBlindingParameters((RsaKeyParameters)pair.Public, blindingFactor);


// "Blind" the signature
PssSigner signer = new PssSigner(new RsaBlindingEngine(), new Sha256Digest(), 20);

signer.Init(true, blindingParams);

signer.BlockUpdate(data, 0, data.Length);

byte[] sig = signer.GenerateSignature(); // get signature ready to sign


// Sign the blinded message

RsaEngine engine = new RsaEngine();
engine.Init(true, pair.Private);

var blindsign = engine.ProcessBlock(sig, 0, sig.Length);

// Unblind signature
RsaBlindingEngine blindingEngine = new RsaBlindingEngine();
blindingEngine.Init(false, blindingParams);
byte[] signew = blindingEngine.ProcessBlock(blindsign, 0, blindsign.Length);

// Verify signature
signer = new PssSigner(new RsaEngine(), new Sha256Digest(), 20);
signer.Init(false,pair.Public);
signer.BlockUpdate(data, 0,data.Length);
var rtn=signer.VerifySignature(signew);


RsaPrivateCrtKeyParameters priv = ((RsaPrivateCrtKeyParameters)pair.Private);


Console.WriteLine("Message:\t{0}",str);
Console.WriteLine("Key size:\t{0}",size);
Console.WriteLine("RSA N:\t{0}",priv.Modulus);
Console.WriteLine("RSA d:\t{0}",priv.Exponent);
Console.WriteLine(" p:\t{0}",priv.P);
Console.WriteLine(" q:\t{0}",priv.Q);
Console.WriteLine("RSA e:\t{0}",priv.PublicExponent);

Console.WriteLine("\nVerified: {0}",rtn);
Console.WriteLine("\nBlinded signature: {0}",Convert.ToHexString(sig));
Console.WriteLine("\nUnblinded signature: {0}",Convert.ToHexString(signew));


} catch (Exception e) {
Console.WriteLine("Error: {0}",e.Message);
}

}
}
}

A sample run with 512-bit RSA keys is [here]:

Message:	Hello
Key size: 512
RSA N: 12511808572143989916826935471968780208908487853817042371503250329054594731816804697757127207525520537191353207439652358352576696463755572194510894258323537
RSA d: 279399909140374586009066940250946943493561987488918343999496572265611782504746421197209479739716734056450274448459171621478307712377492054761751694218441
p: 114126233414209388805165443682131385133344438844833007416623062344199584665989
q: 109631310855004490104097502654583721981446058027146991642196967547001620023133
RSA e: 65537
Blinded signature: D3EFF467903E6B872FBAA634E3F246285CAD485061153665003BC04359BCBD37B84870D6E35FAD18EE141E7B201F72C8C89AB21DAD1F927CC97186B1A10CEF5F
Blinded signature: 0+/0Z5A+a4cvuqY04/JGKFytSFBhFTZlADvAQ1m8vTe4SHDW41+tGO4UHnsgH3LIyJqyHa0fknzJcYaxoQzvXw==

and for 1,024-bit keys [here]:

Message:	Hello
Key size: 1024
RSA N: 106527874199091876611505214510812164191071760249005839016323942672135056253079603784358786625978008704715367848088164641333941182587969738418475081021651999716407938202597563491610456850393092861346738384805024668843896870269491049288869358499614624931479067217390575400679253272869790411036988814240049511937
RSA d: 15216487475305533580305844761084826480421030943503059253726605357809282897759980838711629377827112401967470745002609293412995224945707728121745244037271943910349898605716694163218685271545709592351237335455299440755160838786123251280296489196623692979293016514957716524295761912355716573213090596239212508593
p: 13062374440445217926754453343419991884841707438788698549377625968377569805783947066521723695671999553236666244885348386499214476877871889108559750772586227
q: 8155322348534741659379067491940447016712782401584384431481706714717077320981141889254756356892671571918358354363903656019784423043888813207301306403740731
RSA e: 65537
Blinded signature: 7D8FF51B7C57C36F20065BA69B676368EDC5D5B5BEE2286AD09FBE23A7EF3A06A3A65FAA68C073CD9C9E2A63A4E181E4D05A39F80F52C71041C9DE78FF3D9091E4FEA9C27A1216874C29AB8728E4597FF40966D69FE5E4A784CC6C30AAAE838EF3E29377A0B4522B2C6B22F05FBA44591621CDEE28059D808466C7CFD775E4DB
Blinded signature: fY/1G3xXw28gBlumm2djaO3F1bW+4ihq0J++I6fvOgajpl+qaMBzzZyeKmOk4YHk0Fo5+A9SxxBByd54/z2QkeT+qcJ6EhaHTCmrhyjkWX/0CWbWn+Xkp4TMbDCqroOO8+KTd6C0UissayLwX7pEWRYhze4oBZ2AhGbHz9d15Ns=

Conclusions

And so David showed us a new way of transacting, and in a trusted way. At the core of his work was the rights to privacy. We need to follow David’s path in the future and build a more trusted digital work, and which has increased levels of trust.

Reference

[1] Chaum, D. (1983). Blind signatures for untraceable payments. In Advances in cryptology (pp. 199–203). Springer, Boston, MA.