独自暗号貨幣を作ろう 第11回

第1回 第2回 第3回 第4回 第5回 第6回 第7回 第8回 第9回 第10回


<修正1>
TXBLOCKBASE抽象クラスのId仮想プロパティの実装が間違っていたので修正します。
IdCacheを計算した後はIsModifiedフィールドを偽に変更しなければなりませんでした。

public abstract class TXBLOCKBASE<TxidBlockidHashType> : SHAREDDATA
    where TxidBlockidHashType : HASHBASE
{
    public TXBLOCKBASE(int? _version) : base(_version) { }
 
    protected bool isModified;
 
    protected TxidBlockidHashType idCache;
    public virtual TxidBlockidHashType Id
    {
        get
        {
            if (isModified || idCache == null)
            {
                idCache = Activator.CreateInstance(typeof(TxidBlockidHashType), ToBinary()) as TxidBlockidHashType;
                isModified = false;
            }
            return idCache;
        }
    }
 
    public virtual bool IsValid { get { return true; } }
}


<修正2>
貨幣を移動する取引に含まれる取引入力に署名を行った際にisModifiedフィールドを真に変更するのを忘れていました。修正します。

public class TransferTransaction<TxidHashType, PubKeyHashType, PubKeyType> : Transaction<TxidHashType, PubKeyHashType>
    where TxidHashType : HASHBASE
    where PubKeyHashType : HASHBASE
    where PubKeyType : DSAPUBKEYBASE
{
(中略)
    public void Sign(TransactionOutput<PubKeyHashType>[] prevTxOutputs, DSAPRIVKEYBASE[] privKeys)
    {
        if (prevTxOutputs.Length != inputs.Length)
            throw new ArgumentException("inputs_and_prev_outputs");
        if (privKeys.Length != inputs.Length)
            throw new ArgumentException("inputs_and_priv_keys");
 
        byte[] bytesToSign = GetBytesToSign(prevTxOutputs);
 
        for (int i = 0; i < inputs.Length; i++)
            inputs[i].SetSenderSig(privKeys[i].Sign(bytesToSign));
 
        //取引入力の内容が変更された
        isModified = true;
    }
(中略)
}


<改良1>
今まで楕円曲線DSAの公開鍵及び秘密鍵を可変長としていましたが、直列化する場合に必要なデータ長の削減のために固定長に変更します。

DSAPUBKEYBASE抽象クラス及びDSAPRIVKEYBASE抽象クラスにSizeByte抽象プロパティを追加し、StreamInfo抽象プロパティの実装を変更します。DSAKEYPAIRBASEクラスの実装も変更します。

public abstract class DSAPUBKEYBASE : SHAREDDATA
{
    public DSAPUBKEYBASE() : base(null) { }
 
    public DSAPUBKEYBASE(byte[] _pubKey)
        : base(null)
    {
        if (_pubKey.Length != SizeByte)
            throw new InvalidOperationException("invalid_length_pub_key");
 
        pubKey = _pubKey;
    }
 
    public byte[] pubKey { get; private set; }
 
    public abstract int SizeByte { get; }
 
    public abstract bool Verify(byte[] data, byte[] signature);
 
    protected override Func<ReaderWriter, IEnumerable<MainDataInfomation>> StreamInfo
    {
        get
        {
            return (msrw) => new MainDataInfomation[]{
                new MainDataInfomation(typeof(byte[]), SizeByte, () => pubKey, (o) => pubKey = (byte[])o),
            };
        }
    }
}
 
public abstract class DSAPRIVKEYBASE : SHAREDDATA
{
    public DSAPRIVKEYBASE() : base(null) { }
 
    public DSAPRIVKEYBASE(byte[] _privKey)
        : base(null)
    {
        if (_privKey.Length != SizeByte)
            throw new InvalidOperationException("invalid_length_priv_key");
 
        privKey = _privKey;
    }
 
    public byte[] privKey { get; private set; }
 
    public abstract int SizeByte { get; }
 
    public abstract byte[] Sign(byte[] data);
 
    protected override Func<ReaderWriter, IEnumerable<MainDataInfomation>> StreamInfo
    {
        get
        {
            return (msrw) => new MainDataInfomation[]{
                new MainDataInfomation(typeof(byte[]), SizeByte, () => privKey, (o) => privKey = (byte[])o),
            };
        }
    }
}
 
public abstract class DSAKEYPAIRBASE<DsaPubKeyType, DsaPrivKeyType> : SHAREDDATA
    where DsaPubKeyType : DSAPUBKEYBASE
    where DsaPrivKeyType : DSAPRIVKEYBASE
{
    public DSAKEYPAIRBASE() : base(null) { }
 
    public DsaPubKeyType pubKey { get; protected set; }
    public DsaPrivKeyType privKey { get; protected set; }
 
    protected override Func<ReaderWriter, IEnumerable<MainDataInfomation>> StreamInfo
    {
        get
        {
            return (msrw) => new MainDataInfomation[]{
                new MainDataInfomation(typeof(DsaPubKeyType), null, () => pubKey, (o) => pubKey = (DsaPubKeyType)o),
                new MainDataInfomation(typeof(DsaPrivKeyType), null, () => privKey, (o) => privKey = (DsaPrivKeyType)o),
            };
        }
    }
}


具象クラスにSizeByte抽象プロパティを実装します。それ程大きな変更ではないので、コードは示しません。


<改良2>
更に取引入力の署名も可変長から固定長に変更します。senderSigLength静的フィールドを追加します。

public class TransactionInput<TxidHashType, PubKeyType> : SHAREDDATA
    where TxidHashType : HASHBASE
    where PubKeyType : DSAPUBKEYBASE
{
(中略)
    public static readonly int senderSigLength = 64;
(中略)
    protected override Func<ReaderWriter, IEnumerable<MainDataInfomation>> StreamInfo
    {
        get
        {
            return (msrw) => new MainDataInfomation[]{
                new MainDataInfomation(typeof(TxidHashType), null, () => prevTxHash, (o) => prevTxHash = (TxidHashType)o),
                new MainDataInfomation(typeof(int), () => prevTxOutputIndex, (o) => prevTxOutputIndex = (int)o),
                new MainDataInfomation(typeof(byte[]), senderSigLength, () => senderSig, (o) => senderSig = (byte[])o),
                new MainDataInfomation(typeof(PubKeyType), null, () => senderPubKey, (o) => senderPubKey = (PubKeyType)o),
            };
        }
    }
(中略)
    public void SetSenderSig(byte[] sig)
    {
        if (sig.Length != senderSigLength)
            throw new ArgumentException("tx_in_sender_sig_length");
 
        senderSig = sig;
    }
}