dsa算法(6)

1.3.3. LocalDataStructures遍

LocalDataStructures派生自DataStructures。该Pass为程序中的所有函数计算局部数据结构图。Chris Latter论文中给出的局部分析的伪代码算法(具体算法请参考Chris的论文)。不过,DSA的实现实际已经大大突破了论文中的定义。

 

1442  bool LocalDataStructures::runOnModule(Module&M) {

1443    init(&getAnalysis<DataLayout>());

1444    addrAnalysis =&getAnalysis<AddressTakenAnalysis>();

1445 

1446    // First step,build the globals graph.

1447    {

1448      GraphBuilder GGB(*GlobalsGraph);

1449 

1450      // Addinitializers for all of the globals to the globals graph.

1451      for(Module::global_iterator I = M.global_begin(), E = M.global_end();

1452           I != E; ++I)

1453        if (!(I->hasSection() &&I->getSection() == "llvm.metadata")) {

1454          if (I->isDeclaration())

1455            GGB.mergeExternalGlobal(I);

1456          else

1457            GGB.mergeInGlobalInitializer(I);

1458        }

 

1443行调用的是DataStructures::init,它为全局对象(包括函数)构建了一个DSGraph实例(1448行的GlobalsGraph)。1444行获取这个Pass所依赖的AddressTakenAnalysis对象(它是全局唯一的)。1448行的GraphBuilder是数据结构图(datastructure graph)的构造器,它继承自InstVisitor<GraphBuilder>。InstVisitor是各种指令访问者(instructionvistor)的基类。显然,GraphBuilder是一个指令访问者。指令访问者的好处是:使用它,你无需使用大量的转换或者巨大的switch语句块来对不同类型的指令执行不同的操作,但你必须重载必要的的visitXXX方法。

 

210        explicit GraphBuilder(DSGraph& g)

211          :G(g), FB(0), TD(g.getDataLayout()),VAArray(0)

212        {}

 

在llvm IR中一个对象是否是声明由下面的方法来判断。这是一个简单实用的方法。

 

66      bool GlobalValue::isDeclaration() const {

67        // Globals aredefinitions if they have an initializer.

68        if (constGlobalVariable *GV = dyn_cast<GlobalVariable>(this))

69          returnGV->getNumOperands() == 0;

70     

71        // Functions aredefinitions if they have a body.

72        if (constFunction *F = dyn_cast<Function>(this))

73          returnF->empty();

74     

75        // Aliases arealways definitions.

76        assert(isa<GlobalAlias>(this));

77        return false;

78      }

 

对于声明,比如全局对象的初始值,我们不掌握其细节,通过下面的方法来处理。

1.3.3.1. 全局对象声明的处理

在LocalDataStructures::runOnModule的1453行,getSection方法给出这个全局对象注入的节,在llvm文件中,节“llvm.metadata”用于保存调试信息。放入这个节的都是调试数据。如果不是调试数据,对这些全局对象声明调用下面的方法:

 

1390  void GraphBuilder::mergeExternalGlobal(GlobalVariable*GV) {

1391    // Get a nodehandle to the global node and merge the initializer into it.

1392    DSNodeHandle NH = getValueDest(GV);

1393  }

 

方法getValueDest返回图中代表实际值的DSNode(封装在DSNodeHandle中)。我们已经知道,DSNodeHandle相当于指向对应DSNode的指针,它的实例由一个DSNode与一个偏移量组成。DSNode则表示一个指定大小的内存对象,显然DSNodeHandle的实例表示对这个对象的一次援引。

 

249    DSNodeHandle GraphBuilder::getValueDest(Value* V) {

250      if (isa<Constant>(V) &&cast<Constant>(V)->isNullValue())

251        return0;  // Nulldoesn't point to anything, don't add to ScalarMap!

252   

253      DSNodeHandle &NH = G.getNodeForValue(V);

254      if (!NH.isNull())

255        returnNH;     //Already have a node?  Just return it...

256   

257      // Otherwise weneed to create a new node to point to.

258      // Check first forconstant expressions that must be traversed to

259      // extract theactual value.

260      DSNode* N;

261      if (Function * F = dyn_cast<Function >(V)) {

262        // Create a newglobal node for this function.

263        N = createNode();

264        N->addFunction(F);

265        if (F->isDeclaration())

266          N->setExternFuncMarker();

267      } else if (GlobalValue * GV =dyn_cast<GlobalValue > (V)) {

268        // Create a newglobal node for this global variable.

269        N = createNode();

270        N->addGobal(GV);

271        if (GV->isDeclaration())

272          N->setExternGlobalMarker();

 

注意253行的getNodeForValue,如果V还未加入G的ScalarMap,它把V插入,与一个缺省构造的DSNodeHandle关联,并返回这个DSNodeHandle。此时,满足254行条件。如果这个指定的内存对象尚未产生,GraphBuilder的createNode方法就在DSGraph中创建一个DSNode,下面92行的G就是GraphBuilder中保存的DSGraph对象。

 

90          DSNode *createNode()

91          {  

92            DSNode* ret = new DSNode(&G);

93            assert(ret->getParentGraph()&& "No parent?");

94            returnret;

95          }

 

264行的addFunction主要是调用addGlobal方法。每个函数都有一个对应的DSGraph,每个图分配有一个DSScalarMap实例记录该函数中的全局对象。

 

208    void DSNode::addGlobal(const GlobalValue *GV) {

209      // First, check tomake sure this is the leader if the global is in an

210      // equivalenceclass.

211      GV = getParentGraph()->getScalarMap().getLeaderForGlobal(GV);

212   

213      Globals.insert(GV);

214      setGlobalMarker();

215    }

 

DSScalarMap中的GlobalECs是保存同类(在离散数学里,同类被定义为满足自反、传递及对称的关系)的集合。一个同类关系被组织为一个链表(ECValue实例),其中一个称为领导者(Leader)的对象作为该同类的代表。因此,getLeaderForGlobal返回同类集的Leader,如果存在的话,否则就是GV本身。

 

65        constGlobalValue *getLeaderForGlobal(const GlobalValue *GV) const{

66          EquivalenceClasses<const GlobalValue*>::iterator ECI =GlobalECs.findValue(GV);

67          if (ECI == GlobalECs.end()) return GV;

68          return*GlobalECs.findLeader(ECI);

69        }

 

GraphBuilder::getValueDest余下的部分,除了UndefValue(293~295行),其它的处理对象都是定义。最后,DSNode与DSNodeHandle必须绑定,这由在getValueDest 327行的setTo完成(代码在下面显示)。

1.3.3.2. 全局对象定义的处理

全局对象的定义的处理则稍微复杂一些,因为对于变量这涉及确认内存的大小及初始值的优化处理。在LocalDataStructures::runOnModule的1457行,调用下面的函数。

 

1359  void GraphBuilder::mergeInGlobalInitializer(GlobalVariable*GV) {

1360    // Ensure that theglobal variable is not external

1361    assert(!GV->isDeclaration()&& "Cannot merge in external global!");

1362 

1363    //

1364    // Get a nodehandle to the global node and merge the initializer into it.

1365    //

1366    DSNodeHandle NH = getValueDest(GV);

1367 

1368    //

1369    // Ensure that theDSNode is large enough to hold the new constant that we'll

1370    // be adding to it.

1371    //

1372    Type * ElementType =GV->getType()->getElementType();

1373    while(ArrayType*ATy = dyn_cast<ArrayType>(ElementType)) {

1374      ElementType = ATy->getElementType();

1375    }

1376   if(!NH.getNode()->isNodeCompletelyFolded()) {

1377      unsigned requiredSize =TD.getTypeAllocSize(ElementType) + NH.getOffset();

1378      if (NH.getNode()->getSize() <requiredSize){

1379        NH.getNode()->growSize (requiredSize);

1380      }

1381    }

1382 

1383    //

1384    // Do the actualmerging in of the constant initializer.

1385    //

1386    MergeConstantInitIntoNode(NH,GV->getType()->getElementType(), GV->getInitializer());

1387 

1388  }

 

同样,首先通过GraphBuilder::getValueDest,为这些定义产生对应的DSNode。

1.3.3.2.1. 变量及函数定义的DSNode

为变量及函数定义产生DSNode的过程与声明基本类似,除了定义使用的DSNode不需要记上外部标记。

1.3.3.2.2. 常量的DSNode
1.3.3.2.2.1. ConstantExpr

LlvmIR中的常量类型的公共基类就是Constant,它也是Value的派生类。下面274行的ConstantExpr表示一个使用常量值的表达式,它通常由一个操作符及两个常量组成。275行的isCast方法检测这个表达式是否是一个转换,llvm IR定义了如下的转换(通过源文件instruction.def及系列的宏):截断、0扩展、符号扩展、浮点到无符号整数、浮点到有符号整数、无符号整数到浮点、有符号整数到浮点、浮点截断为整数、浮点控制为整数、指针到整数、整数到指针、无需操作的转换。显然,转换可视为一个一元操作符,如果被转换常量是一个指针类型,使用getVlueDest处理,也同样会通过createNode创建一个新节点,不过没有Unknown标记。

 

GraphBuilder::getValueDest(续)

 

273      } else if (Constant *C =dyn_cast<Constant>(V)) {

274        if (ConstantExpr *CE =dyn_cast<ConstantExpr>(C)) {

275         if (CE->isCast()) {

276            if(isa<PointerType>(CE->getOperand(0)->getType()))

277              NH = getValueDest(CE->getOperand(0));

278            else

279              NH = createNode()->setUnknownMarker();

280          } else if (CE->getOpcode() ==Instruction::GetElementPtr) {

281            visitGetElementPtrInst(*CE);

282            assert(G.hasNodeForValue(CE)&& "GEP didn't get processed right?");

283            NH = G.getNodeForValue(CE);

284          } else {

285            // Thisreturns a conservative unknown node for any unhandled ConstExpr

286            NH = createNode()->setUnknownMarker();

287          }

288          if (NH.isNull()) {  // (getelementptrnull, X) returns null

289            G.eraseNodeForValue(V);

290            return0;

291          }

292          returnNH;

 

注意,对ConstantExpr的处理在292行退出getValueDest函数。

### DSA算法详解 #### 算法概述 DSA(Digital Signature Algorithm)是一种基于离散对数问题的数字签名算法。它主要用于生成和验证数字签名,广泛应用于信息安全领域中的身份验证和数据完整性保护[^1]。 #### 算法原理 DSA的核心思想是利用模幂运算以及离散对数问题来实现签名的安全性和不可伪造性。以下是其主要过程: 1. **参数生成** - 选择一个素数 \( p \),使得 \( p-1 \) 是另一个大素数 \( q \) 的倍数。 - 计算基元 \( g \),满足 \( g = h^{(p-1)/q} \mod p \),其中 \( h \) 是一个小于 \( p-1 \) 的随机数。 - 私钥 \( x \) 和公钥 \( y \) 的关系为:\( y = g^x \mod p \)。 2. **签名生成** 对消息 \( m \) 进行哈希处理得到摘要 \( H(m) \)。随后执行以下操作: - 随机选取临时私钥 \( k \),并计算 \( r = (g^k \mod p) \mod q \)。 - 使用 \( s = k^{-1}(H(m)+xr) \mod q \) 来生成签名部分 \( s \)。 - 最终签名为一对值 \( (r, s) \)[^2]。 3. **签名验证** 接收方收到消息及其签名后,按照如下步骤验证签名的有效性: - 计算 \( w = s^{-1} \mod q \)。 - 计算 \( u_1 = H(m)w \mod q \) 和 \( u_2 = rw \mod q \)。 - 计算 \( v = ((g^{u_1}y^{u_2})\mod p)\mod q \)。 - 如果 \( v = r \),则签名有效;否则无效。 #### 安全性分析 DSA的安全性依赖于以下几个方面: 1. **离散对数难题** 攻击者难以从已知的 \( y = g^x \mod p \) 中推导出私钥 \( x \)。这是DSA算法的主要安全保障之一。 2. **哈希函数的选择** 在实际应用中,通常使用SHA系列哈希函数(如SHA-256)代替早期不安全的MD5或SHA-1。这可以防止攻击者通过碰撞攻击伪造签名。 3. **随机数的重要性** 临时私钥 \( k \) 必须每次都是真正随机且保密的。如果重复使用相同的 \( k \),可能会泄露私钥信息。 尽管如此,在某些场景下,更现代的算法(如Ed25519)可能提供更高的性能和安全性[^3]。 --- ### 示例代码 以下是一个简单的Python示例,演示如何使用`cryptography`库生成和验证DSA签名。 ```python from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import utils # 参数生成 private_key = dsa.generate_private_key(key_size=2048) public_key = private_key.public_key() # 消息签名 message = b"Hello, this is a test message." hash_algorithm = hashes.SHA256() signature = private_key.sign(message, hash_algorithm) # 签名验证 try: public_key.verify(signature, message, hash_algorithm) print("Signature verified successfully.") except Exception as e: print(f"Verification failed: {e}") ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值