Why Nostr? What is Njump?
2023-02-04 09:40:54
in reply to

mike on Nostr: This is what you guys need to worry about instead of ordinals (cc: #[3] #[6] #[4] ...

This is what you guys need to worry about instead of ordinals (cc: ) 😉

"The private key
* MUST be set before generating the signature itself, but message
* data can be input before setting the key.
*
* Instances are NOT thread-safe. However, once a signature has
* been generated, the same instance can be used again for another
* signature; {@link #setPrivateKey} need not be called again if the
* private key has not changed. {@link #reset} can also be called to
* cancel previously input data. Generating a signature with {@link
* #sign} (not {@link #signHash}) also implicitly causes a
* reset.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted pursuant to, and subject to the license
* terms contained in, the Simplified BSD License set forth in Section
* 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
* (http://trustee.ietf.org/license-info)."


https://www.rfc-editor.org/rfc/rfc6979

A.3. Sample Code

We include here a sample implementation of deterministic DSA. It is
meant for illustration purposes; for instance, this code makes no
attempt at avoiding side-channel leakage of the private key. It is
written in the Java programming language. The actual generation of
the "random" value k is done in the computek() method. The Java
virtual machine (JVM) is assumed to provide the implementation of the
hash function and of HMAC.

// ==================================================================

import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
* Deterministic DSA signature generation. This is a sample
* implementation designed to illustrate how deterministic DSA
* chooses the pseudorandom value k when signing a given message.
* This implementation was NOT optimized or hardened against
* side-channel leaks.
*
* An instance is created with a hash function name, which must be
* supported by the underlying Java virtual machine ("SHA-1" and
* "SHA-256" should work everywhere). The data to sign is input
* through the {@code update()} methods. The private key is set with
* {@link #setPrivateKey}. The signature is obtained by calling
* {@link #sign}; alternatively, {@link #signHash} can be used to
* sign some data that has been externally hashed. The private key
* MUST be set before generating the signature itself, but message
* data can be input before setting the key.
*
* Instances are NOT thread-safe. However, once a signature has
* been generated, the same instance can be used again for another
* signature; {@link #setPrivateKey} need not be called again if the
* private key has not changed. {@link #reset} can also be called to
* cancel previously input data. Generating a signature with {@link
* #sign} (not {@link #signHash}) also implicitly causes a
* reset.
*
* ------------------------------------------------------------------
* Copyright (c) 2013 IETF Trust and the persons identified as
* authors of the code. All rights reserved.
*



Pornin Informational [Page 70]

RFC 6979 Deterministic DSA and ECDSA August 2013


* Redistribution and use in source and binary forms, with or without
* modification, is permitted pursuant to, and subject to the license
* terms contained in, the Simplified BSD License set forth in Section
* 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
* (http://trustee.ietf.org/license-info).
*
* Technical remarks and questions can be addressed to:
* pornin@bolet.org
* ------------------------------------------------------------------
*/

public class DeterministicDSA {

private String macName;
private MessageDigest dig;
private Mac hmac;
private BigInteger p, q, g, x;
private int qlen, rlen, rolen, holen;
private byte[] bx;

/**
* Create an instance, using the specified hash function.
* The name is used to obtain from the JVM an implementation
* of the hash function and an implementation of HMAC.
*
* @param hashName the hash function name
* @throws IllegalArgumentException on unsupported name
*/
public DeterministicDSA(String hashName)
{
try {
dig = MessageDigest.getInstance(hashName);
} catch (NoSuchAlgorithmException nsae) {
throw new IllegalArgumentException(nsae);
}
if (hashName.indexOf('-') < 0) {
macName = "Hmac" + hashName;
} else {
StringBuilder sb = new StringBuilder();
sb.append("Hmac");
int n = hashName.length();
for (int i = 0; i < n; i ++) {
char c = hashName.charAt(i);
if (c != '-') {
sb.append(c);
}
}
macName = sb.toString();



Pornin Informational [Page 71]

RFC 6979 Deterministic DSA and ECDSA August 2013


}
try {
hmac = Mac.getInstance(macName);
} catch (NoSuchAlgorithmException nsae) {
throw new IllegalArgumentException(nsae);
}
holen = hmac.getMacLength();
}

/**
* Set the private key.
*
* @param p key parameter: field modulus
* @param q key parameter: subgroup order
* @param g key parameter: generator
* @param x private key
*/
public void setPrivateKey(BigInteger p, BigInteger q,
BigInteger g, BigInteger x)
{
/*
* Perform some basic sanity checks. We do not
* check primality of p or q because that would
* be too expensive.
*
* We reject keys where q is longer than 999 bits,
* because it would complicate signature encoding.
* Normal DSA keys do not have a q longer than 256
* bits anyway.
*/
if (p == null || q == null || g == null || x == null
|| p.signum() <= 0 || q.signum() <= 0
|| g.signum() <= 0 || x.signum() <= 0
|| x.compareTo(q) >= 0 || q.compareTo(p) >= 0
|| q.bitLength() > 999
|| g.compareTo(p) >= 0 || g.bitLength() == 1
|| g.modPow(q, p).bitLength() != 1) {
throw new IllegalArgumentException(
"invalid DSA private key");
}
this.p = p;
this.q = q;
this.g = g;
this.x = x;
qlen = q.bitLength();
if (q.signum() <= 0 || qlen < 8) {
throw new IllegalArgumentException(
"bad group order: " + q);



Pornin Informational [Page 72]

RFC 6979 Deterministic DSA and ECDSA August 2013


}
rolen = (qlen + 7) >>> 3;
rlen = rolen * 8;

/*
* Convert the private exponent (x) into a sequence
* of octets.
*/
bx = int2octets(x);
}

private BigInteger bits2int(byte[] in)
{
BigInteger v = new BigInteger(1, in);
int vlen = in.length * 8;
if (vlen > qlen) {
v = v.shiftRight(vlen - qlen);
}
return v;
}

private byte[] int2octets(BigInteger v)
{
byte[] out = v.toByteArray();
if (out.length < rolen) {
byte[] out2 = new byte[rolen];
System.arraycopy(out, 0,
out2, rolen - out.length,
out.length);
return out2;
} else if (out.length > rolen) {
byte[] out2 = new byte[rolen];
System.arraycopy(out, out.length - rolen,
out2, 0, rolen);
return out2;
} else {
return out;
}
}

private byte[] bits2octets(byte[] in)
{
BigInteger z1 = bits2int(in);
BigInteger z2 = z1.subtract(q);
return int2octets(z2.signum() < 0 ? z1 : z2);
}

/**



Pornin Informational [Page 73]

RFC 6979 Deterministic DSA and ECDSA August 2013


* Set (or reset) the secret key used for HMAC.
*
* @param K the new secret key
*/
private void setHmacKey(byte[] K)
{
try {
hmac.init(new SecretKeySpec(K, macName));
} catch (InvalidKeyException ike) {
throw new IllegalArgumentException(ike);
}
}

/**
* Compute the pseudorandom k for signature generation,
* using the process specified for deterministic DSA.
*
* @param h1 the hashed message
* @return the pseudorandom k to use
*/
private BigInteger computek(byte[] h1)
{
/*
* Convert hash value into an appropriately truncated
* and/or expanded sequence of octets. The private
* key was already processed (into field bx[]).
*/
byte[] bh = bits2octets(h1);

/*
* HMAC is always used with K as key.
* Whenever K is updated, we reset the
* current HMAC key.
*/

/* step b. */
byte[] V = new byte[holen];
for (int i = 0; i < holen; i ++) {
V[i] = 0x01;
}

/* step c. */
byte[] K = new byte[holen];
setHmacKey(K);

/* step d. */
hmac.update(V);
hmac.update((byte)0x00);



Pornin Informational [Page 74]

RFC 6979 Deterministic DSA and ECDSA August 2013


hmac.update(bx);
hmac.update(bh);
K = hmac.doFinal();
setHmacKey(K);

/* step e. */
hmac.update(V);
V = hmac.doFinal();

/* step f. */
hmac.update(V);
hmac.update((byte)0x01);
hmac.update(bx);
hmac.update(bh);
K = hmac.doFinal();
setHmacKey(K);

/* step g. */
hmac.update(V);
V = hmac.doFinal();

/* step h. */
byte[] T = new byte[rolen];
for (;;) {
/*
* We want qlen bits, but we support only
* hash functions with an output length
* multiple of 8;acd hence, we will gather
* rlen bits, i.e., rolen octets.
*/
int toff = 0;
while (toff < rolen) {
hmac.update(V);
V = hmac.doFinal();
int cc = Math.min(V.length,
T.length - toff);
System.arraycopy(V, 0, T, toff, cc);
toff += cc;
}
BigInteger k = bits2int(T);
if (k.signum() > 0 && k.compareTo(q) < 0) {
return k;
}

/*
* k is not in the proper range; update
* K and V, and loop.
*/



Pornin Informational [Page 75]

RFC 6979 Deterministic DSA and ECDSA August 2013


hmac.update(V);
hmac.update((byte)0x00);
K = hmac.doFinal();
setHmacKey(K);
hmac.update(V);
V = hmac.doFinal();
}
}

/**
* Process one more byte of input data (message to sign).
*
* @param in the extra input byte
*/
public void update(byte in)
{
dig.update(in);
}

/**
* Process some extra bytes of input data (message to sign).
*
* @param in the extra input bytes
*/
public void update(byte[] in)
{
dig.update(in, 0, in.length);
}

/**
* Process some extra bytes of input data (message to sign).
*
* @param in the extra input buffer
* @param off the extra input offset
* @param len the extra input length (in bytes)
*/
public void update(byte[] in, int off, int len)
{
dig.update(in, off, len);
}

/**
* Produce the signature. {@link #setPrivateKey} MUST have
* been called. The signature is computed over the data
* that was input through the {@code update*()} methods.
* This engine is then reset (made ready for a new
* signature generation).
*



Pornin Informational [Page 76]

RFC 6979 Deterministic DSA and ECDSA August 2013


* @return the signature
*/
public byte[] sign()
{
return signHash(dig.digest());
}

/**
* Produce the signature. {@link #setPrivateKey} MUST
* have been called. The signature is computed over the
* provided hash value (data is assumed to have been hashed
* externally). The data that was input through the
* {@code update*()} methods is ignored, but kept.
*
* If the hash output is longer than the subgroup order
* (the length of q, in bits, denoted 'qlen'), then the
* provided value {@code h1} can be truncated, provided that
* at least qlen leading bits are preserved. In other words,
* bit values in {@code h1} beyond the first qlen bits are
* ignored.
*
* @param h1 the hash value
* @return the signature
*/
public byte[] signHash(byte[] h1)
{
if (p == null) {
throw new IllegalStateException(
"no private key set");
}
try {
BigInteger k = computek(h1);
BigInteger r = g.modPow(k, p).mod(q);
BigInteger s = k.modInverse(q).multiply(
bits2int(h1).add(x.multiply(r)))
.mod(q);

/*
* Signature encoding: ASN.1 SEQUENCE of
* two INTEGERs. The conditions on q
* imply that the encoded version of r and
* s is no longer than 127 bytes for each,
* including DER tag and length.
*/
byte[] br = r.toByteArray();
byte[] bs = s.toByteArray();
int ulen = br.length + bs.length + 4;
int slen = ulen + (ulen >= 128 ? 3 : 2);



Pornin Informational [Page 77]

RFC 6979 Deterministic DSA and ECDSA August 2013


byte[] sig = new byte[slen];
int i = 0;
sig[i ++] = 0x30;
if (ulen >= 128) {
sig[i ++] = (byte)0x81;
sig[i ++] = (byte)ulen;
} else {
sig[i ++] = (byte)ulen;
}
sig[i ++] = 0x02;
sig[i ++] = (byte)br.length;
System.arraycopy(br, 0, sig, i, br.length);
i += br.length;
sig[i ++] = 0x02;
sig[i ++] = (byte)bs.length;
System.arraycopy(bs, 0, sig, i, bs.length);
return sig;

} catch (ArithmeticException ae) {
throw new IllegalArgumentException(
"DSA error (bad key ?)", ae);
}
}

/**
* Reset this engine. Data input through the {@code
* update*()} methods is discarded. The current private key,
* if one was set, is kept unchanged.
*/
public void reset()
{
dig.reset();
}
}

// ==================================================================















Pornin Informational [Page 78]

RFC 6979 Deterministic DSA and ECDSA August 2013


Author's Address

Thomas Pornin
Quebec, QC
Canada

EMail: pornin@bolet.org

Author Public Key
npub14fk5v6ancupzp30kwycx48j5qkfvvjmgxxxn23kwtkh78sf3s7vsqec80l