Scrypt proof of workのScriptとは?

https://cryptobook.nakov.com/mac-and-key-derivation/scrypt

Scrypt (RFC 7914) is a strong cryptographic key-derivation function (KDF). It is memory-intensive, designed to prevent GPU, ASIC and FPGA attacks (highly efficient password cracking hardware).

key = Scrypt(password, salt, N, r, p, derived-key-len)

### Script Parameters
N – iterations count (affects memory and CPU usage), e.g. 16384 or 2048
r – block size (affects memory and CPU usage), e.g. 8
p – parallelism factor (threads to run in parallel – affects the memory, CPU usage), usually 1
password– the input password (8-10 chars minimal length is recommended)
salt – securely-generated random bytes (64 bits minimum, 128 bits recommended)
derived-key-length – how many bytes to generate as output, e.g. 32 bytes (256 bits)

The memory in Scrypt is accessed in strongly dependent order at each step, so the memory access speed is the algorithm’s bottleneck. The memory required to compute Scrypt key derivation is calculated as follows:

Memory required = 128 * N * r * p bytes

Choosing parameters depends on how much you want to wait and what level of security (password cracking resistance) do you want to achieve:

Script hash generator
https://8gwifi.org/scrypt.jsp

$ sudo apt-get install python-dev-is-python3
$ pip3 install scrypt

import pyscript

salt = b'aa1f2d3f4d23ac44e9c5a6c3d8f9ee8c'
passwd = b'p@$Sw0rD~7'
key = pyscript.hash(passwd, salt, 2048, 8, 1, 32)
print("Derived key:", key.hex())

Litecoin, Dogecoinとは

### Litecoin
2011年にリリースされた通貨
scryptをproof of workのアルゴリズムとして使用している

– ブロック生成時間 2.5分
– 通貨総発行量: 2140年までに8400万litecoin
– コンセンサスアルゴリズム: Scrypt proof of work
– 開発者はチャーリーリー
https://github.com/litecoin-project/litecoin

Scrypt proof of workは基本的なハッシュ関数としてscryptを使用しているHashcash証明の証明

### Dogecoin
2013年12月にリリースされたもので、Litecoinのフォークに基づくもの。
支払いやチップの利用を促すもので、通貨発行のスピードを速くしている
– ブロック生成時間 60分
– 通貨総発行量: 2015年までに1000億doge
– コンセンサスアルゴリズム: Scrypt proof of work
– Billy MarkusとJackson Palmerが開発者
https://github.com/dogecoin/dogecoin

[C++] for文のautoの書き方

std::vector<int> v;

for(std::vector<int>::const_iterator it = v.begin(), e=v.end(); it != e; ++it){
    std::cout << *it << std::endl;
}

c++11の範囲for文を使うと以下のように書ける

std::vector<int> v;

for(const auto& e: v){
    std::cout << e << std::endl;
}

### 範囲for文(range-based for statement)
配列やコンテナなど複数の要素を持つものから、全ての要素に含まれる値を取り出して処理する

#include <iostream>
using namespace std;

int main() {
    int a[] = {1, 2, 3, 4, 5};
    int sum = 0;
    for(int x : a){
        sum += x;
    }
    cout << "sum = " << sum << end;
    return 0;
}

vector要素の出力

    vector<string> v(5);
    for (int i = 0; i < v.size(); i++){
        string& x = v[i];
        cin >> x;
    }

autoは型推論を行うキーワード

    vector<string> v(5);
    for (auto& x : v){
        cin >> x;
    }

[C++] ヘッダとソースでファイルを分ける

C++ではクラスの定義とそのメンバ関数の定義をヘッダファイルとソースファイルで分割するのが一般的である

### ファイルを分割していない例
c.hpp

#ifndef C_HPP
#define C_HPP

class c {
    private:
    int m_value;

    public:
    int get() {
        return m_value;
    }

    void set(int const value){
        m_value = value;
    }
};

#endif

### ファイルを分割した例
c.hpp

#ifndef C_HPP
#define C_HPP

class c {
    private:
    int m_value;

    public:
    int get();

    void set(int const value);
};

#endif

c.cpp

#include "c.hpp"

int c::get(){
    return m_value;
}

void c::set(int const value){
    m_value = value;
}

インラインで書くこともある

#ifndef C_HPP
#define C_HPP

class c {
private:
int m_value;

public:
int get();

void set(int const value);
};

inline int c::get(){
return m_value;
}

inline void c::set(int const value){
m_value = value;
}

#endif

bitcoinのソースコードで、基本hppとcppのファイル構造になっていたが、謎が解けた。

[C++].hppとは

### .hppとは
ヘッダーファイルで.hpp、.hというファイル形式で保存
.hppはc++が入っている。.hはc言語だがc++でも使用できる

sample.hpp

#ifndef Sample_hpp
#define Sample_hpp

#include <iostream>

using namespace std;

class Sample {
    public:
        string name;
};

#endif

[bitcoin] ASICとは?

ASICとは
L 半導体集積回路の一つで、ある特定の機器や用途のために、必要な機能を組み合わせて設計、製造されるもの。
L フルカスタムICとセミカスタムICがある

複数文字のローカル変数

以下に対応できるようにする
foo = 1;
bar = 2 + 3;
return foo + bar;

typedef struct LVar Lvar;

// local variable
struct LVar {
    LVar *next; // next variable or null
    char *name; // variable name
    int len; // name length
    int offset; // RBP offset
};

LVar *locals;

### if, while, for
アセンブラではcmpを使って、jumpしてend or biginに行くか処理をするか判定している

program = stmt *
stmt = expr ";"
	| "if" "(" expr ")" stmt ("else" stmt)?
	| "while" "(" expr ")" stmt
	| "for" "(" expr? ";" expr? ";" expr? ")" stmt

if

  Aをコンパイルしたコード // スタックトップに結果が入っているはず
  pop rax
  cmp rax, 0
  je  .LendXXX
  Bをコンパイルしたコード
.LendXXX:

if else

  Aをコンパイルしたコード // スタックトップに結果が入っているはず
  pop rax
  cmp rax, 0
  je  .LelseXXX
  Bをコンパイルしたコード
  jmp .LendXXX
.LelseXXX
  Cをコンパイルしたコード
.LendXXX

while

.LbeginXXX:
  Aをコンパイルしたコード
  pop rax
  cmp rax, 0
  je  .LendXXX
  Bをコンパイルしたコード
  jmp .LbeginXXX
.LendXXX:

for

  Aをコンパイルしたコード
.LbeginXXX:
  Bをコンパイルしたコード
  pop rax
  cmp rax, 0
  je  .LendXXX
  Dをコンパイルしたコード
  Cをコンパイルしたコード
  jmp .LbeginXXX
.LendXXX:

関数・ローカル変数とcompiler

以下のような関数処理もコンパイルできるようにする

sum(m, n) {
	acc = 0;
	for (i = m; i <= n; i = i + 1)
		acc = acc + i;
	return acc;
}

main() {
	return sum(1, 10);
}

Cではローカル変数はスタックに置くことにしている、グローバル変数はメモリに置く
関数ごとに呼び出されるメモリ領域を「関数フレーム」「アクティベーションレコード」という
レジスタで関数フレームを常に指しているレジスタをベースレジスタ、値をベースポインタと呼ぶ
ベースレジスタはRBPレジスタを使用する

push rbp
mov rbp, rsp
sub rsp, 16

アルファベットの小文字ならばident

// token type 構造体
typedef enum {
    TK_RESERVED, // op
    TK_INDENT,
    TK_NUM,
    TK_EOF, // end of input
} TokenKind;

program = stmt*
stmt = expr “;”
expr = assign
assign = equality (“=” assign)?
equality = relational (“==” relational | “!=” relational)*
relational = add(“<" add | "<=" add | ">” add | “>=” add)*
add = mul (“+” mul | “-” mul)*
mul = unary (“*” unary | “/” unary)*
unary = (“+” | “-“)? primary
primary = num | “(” expr “)”

Node *assign(){
    Node *node = equality();
    if (consume("="))
        node = new_node(ND_ASSIGN, node, assign());
    return node;
}

Node *expr() {
    return assign();
}

Node *stmt() {
    Node *node = expr();
    expect(";");
    return node;
}

void program() {
    int i = 0;
    while (!at_eof())
        code[i++] = stmt();
    code[i] = NULL;
}

分割コンパイルとリンク

ファイルを分割する
– 9cc.h
– main.c
– parse.c
– codegen.c

Makefile

CFLAGS=-std=c11 -g -static
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)

9cc: $(OBJS)
		$(CC) -o 9cc $(OBJS) $(LDFLAGS)

$(OBJS): 9cc.h

clean:
		rm -f 9cc *.o *~ tmp*

.PHONY: test clean

比較演算子とcompiler

トークナイザ : tokenのlenの追加

// token 
struct Token {
    TokenKind kind; // token type
    Token *next; // next token
    int val; // TK_NUM value
    char *str; // token char
    int len; // length of token
};
bool consume(char *op) {
    if(token->kind != TK_RESERVED || strlen(op) != token->len || memcmp(token->str, op, token->len))
        return false;
    token = token->next;
    return true;
}

演算子の優先順位
1. == !=
2. < <= > >=
3. +, –
4. * /
5. 単項+, –
6. ()

従って

expr = equality
equality = relational (“==” relational | “!=” relational)*
relational = add(“<" add | "<=" add | ">” add | “>=” add)*
add = mul (“+” mul | “-” mul)*
mul = primary (“*” primary | “/” unary)*
unary = (“+” | “-“)? primary
primary = num | “(” expr “)”

### 比較のアセンブリコード
pop rdi
pop rax
cmp rax, rdi // 比較結果はフラグレジスタに保存される
sete al // sete ALで更新すると、自動的にRAXも更新される
movzb rax, al

#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// token type 構造体
typedef enum {
    TK_RESERVED, // op
    TK_NUM,
    TK_EOF, // end of input
} TokenKind;

typedef struct Token Token;

// token 
struct Token {
    TokenKind kind; // token type
    Token *next; // next token
    int val; // TK_NUM value
    char *str; // token char
    int len; // length of token
};

// now focus token
Token *token;

// input program
char *user_input;

// report error
void error_at(char *loc, char *fmt, ...){
    va_list ap;
    va_start(ap, fmt);

    int pos = loc - user_input;
    fprintf(stderr, "%s\n", user_input);
    fprintf(stderr, "%*s", pos, "   "); // output pos blank
    fprintf(stderr, "^ ");
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
    exit(1);
}

void error(char *fmt, ...){
    va_list ap;
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "\n");
    exit(1);
}

// if the next token is expected symbol, read forward one token and 
// return true.
bool consume(char *op) {
    if(token->kind != TK_RESERVED || strlen(op) != token->len || memcmp(token->str, op, token->len))
        return false;
    token = token->next;
    return true;
}

// if the next token is expected symbol, read forward one token and 
// otherwise report an error.
void expect(char *op) {
    if(token->kind != TK_RESERVED || strlen(op) != token->len || memcmp(token->str, op, token->len))
        error_at(token->str, "expected \"%s\"", op);
    token = token->next;
}

// if the next token is expected number, read forward one token and 
// otherwise report an error.
int expect_number() {
    if(token->kind != TK_NUM)
        error("数ではありません");
    int val = token->val;
    token = token->next;
    return val;
}

bool at_eof() {
    return token->kind == TK_EOF;
}

// create a new token and connect it to curl.
Token *new_token(TokenKind kind, Token *cur, char *str, int len){
    Token *tok = calloc(1, sizeof(token));
    tok->kind = kind;
    tok->str = str;
    tok->len = len;
    cur->next = tok;
    return tok;
}

bool startswitch(char *p, char *q) {
    return memcmp(p, q, strlen(q)) == 0;
}

// Tokenize the input string p and return it
Token *tokenize() {
    char *p = user_input;
    Token head;
    head.next = NULL;
    Token *cur = &head;

    while (*p) {
        // skip space
        if(isspace(*p)){
            p++;
            continue;
        }

        if (startswith(p, "==") || startswith(p, "!=") ||
            startswith(p, "<=") || startswith(p, ">=")) {
                cur = new_token(TK_RESERVED, cur, p, 2);
                p += 2;
                continue;
            }
        
        if(strchr("+-*/()<>", *p)){
            cur = new_token(TK_RESERVED, cur, p++, 1);
            continue;
        }

        if(isdigit(*p)) {
            cur = new_token(TK_NUM, cur, p, 0);
            char *q = p;
            cur->val = strtol(p, &p, 10);
            cur->len = p - q;
            continue;
        }
        error_at(p, "invalid token");
    }

    new_token(TK_EOF, cur, p, 0);
    return head.next;
}

typedef enum {
	ND_ADD, // +
	ND_SUB, // -
	ND_MUL, // *
	ND_DIV, // /
    ND_EQ, // ==
    ND_NE, // !=
    ND_LT, // <
    ND_LE, // <=
	ND_NUM, // num
} NodeKind;

typedef struct Node Node;

struct Node {
	NodeKind kind; // node type
	Node *lhs; // left
	Node *rhs; // right
	int val;
};

Node *new_node(NodeKind kind){
    Node *node = calloc(1, sizeof(Node));
    node->kind = kind;
    return node;
}

Node *new_binary(NodeKind kind, Node *lhs, Node *rhs) {
    Node *node = new_node(kind);
    node->lhs = lhs;
    node->rhs = rhs;
    return node;
}

Node *new_num(int val){
    Node *node = new_node(ND_NUM);
    node->val = val;
    return node;
}

Node *expr();
Node *equality();
Node *relational();
Node *add();
Node *mul();
Node *unary();
Node *primary();

Node *expr() {
    return equality();
}

Node *equality(){
    Node *node = relational();

    for(;;){
        if(consume("=="))
            node == new_binary(ND_EQ, node, relational());
        else if (consume("!="))
            node = new_binary(ND_NE, node, relational());
        else
            return node;
    }
}

Node *relational(){
    Node *node = add();

    for(;;) {
        if(consume("<"))
            node = new_binary(ND_LT, node, add());
        else if (consume("<="))
            node = new_binary(ND_LE, node, add());
        else if (consume(">"))
            node = new_binary(ND_LT, add(), node);
        else if (consume(">="))
            node = new_binary(ND_LE, add(), node);
        else
            return node;
    }
}

Node *add() {
    Node *node = mul();

    for(;;) {
        if(consume('+'))
            node = new_binary(ND_ADD, node, mul());
        else if(consume('-'))
            node = new_binary(ND_DIV, node, mul());
        else
            return node;
    }
}

Node *mul() {
    Node *node = unary();

    for(;;) {
        if(consume('*'))
            node = new_binary(ND_MUL, node, unary());
        else if(consume('/'))
            node = new_binary(ND_DIV, node, unary());
        else
            return node;
    }
}

Node *unary() {
    if (consume('+'))
        return unary();
    if (consume('-'))
        return new_binary(ND_SUB, new_node_num(0), unary());
    return primary();
}

Node *primary() {
    if(consume('(')){
        Node *node = expr();
        expect(')');
        return node;
    }

    return new_node_num(expect_number());
}

void gen(Node *node) {
    if(node->kind == ND_NUM) {
        printf("    push %d\n", node->val);
        return;
    }

    gen(node->lhs);
    gen(node->rhs);

    printf("    pop rdi\n");
    printf("    pop rax\n");

    switch(node->kind) {
        case ND_ADD:
            printf("    addd rax, rdi\n");
            break;
        case ND_SUB:
            printf("    sub rax, rdi\n");
            break;
        case ND_MUL:
            printf("    imul rax, rdi\n");
            break;
        case ND_DIV:
            printf("    cqo\n");
            printf("    idiv rdi\n");
            break;
        case ND_EQ:
            printf("    cmp rax, rdi\n");
            printf("    sete al\n");
            printf("    movzb rax, al\n");
            break;
        case ND_NE:
            printf("    cmp rax, rdi\n");
            printf("    sete al\n");
            printf("    movzb rax, al\n");
            break;
        case ND_LT:
            printf("    cmp rax, rdi\n");
            printf("    sete al\n");
            printf("    movzb rax, al\n");
            break;
        case ND_LE:
            printf("    cmp rax, rdi\n");
            printf("    sete al\n");
            printf("    movzb rax, al\n");
            break;
    }
    printf("    push rax\n");    
}



int main(int argc, char **argv){
    if(argc != 2) {
        error("引数の個数が正しくありません\n");
        return 1;
    }

    user_input = argv[1];
    token = tokenize(user_input);
    Node *node = expr();

    printf(".intel_syntax noprefix\n");
    printf(".global main\n");
    printf("main:\n");

    gen(node);

    printf("    pop rax\n");
    printf("    ret\n");
    return 0;
}